aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/video/gspca
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/gspca')
-rw-r--r--drivers/media/video/gspca/Kconfig13
-rw-r--r--drivers/media/video/gspca/Makefile29
-rw-r--r--drivers/media/video/gspca/conex.c1051
-rw-r--r--drivers/media/video/gspca/etoms.c956
-rw-r--r--drivers/media/video/gspca/gspca.c1905
-rw-r--r--drivers/media/video/gspca/gspca.h176
-rw-r--r--drivers/media/video/gspca/jpeg.h301
-rw-r--r--drivers/media/video/gspca/mars.c464
-rw-r--r--drivers/media/video/gspca/ov519.c2186
-rw-r--r--drivers/media/video/gspca/pac207.c622
-rw-r--r--drivers/media/video/gspca/pac7311.c760
-rw-r--r--drivers/media/video/gspca/sonixb.c1477
-rw-r--r--drivers/media/video/gspca/sonixj.c1671
-rw-r--r--drivers/media/video/gspca/spca500.c1216
-rw-r--r--drivers/media/video/gspca/spca501.c2229
-rw-r--r--drivers/media/video/gspca/spca505.c951
-rw-r--r--drivers/media/video/gspca/spca506.c847
-rw-r--r--drivers/media/video/gspca/spca508.c1791
-rw-r--r--drivers/media/video/gspca/spca561.c1052
-rw-r--r--drivers/media/video/gspca/stk014.c592
-rw-r--r--drivers/media/video/gspca/sunplus.c1677
-rw-r--r--drivers/media/video/gspca/t613.c1038
-rw-r--r--drivers/media/video/gspca/tv8532.c670
-rw-r--r--drivers/media/video/gspca/vc032x.c1818
-rw-r--r--drivers/media/video/gspca/zc3xx-reg.h261
-rw-r--r--drivers/media/video/gspca/zc3xx.c7623
26 files changed, 33376 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
new file mode 100644
index 00000000000..42b90742b40
--- /dev/null
+++ b/drivers/media/video/gspca/Kconfig
@@ -0,0 +1,13 @@
+config USB_GSPCA
+ tristate "USB GSPCA driver"
+ depends on VIDEO_V4L2
+ ---help---
+ Say Y here if you want support for various USB webcams.
+
+ See <file:Documentation/video4linux/gspca.txt> for more info.
+
+ This driver uses the Video For Linux API. You must say Y or M to
+ "Video For Linux" to use this driver.
+
+ To compile this driver as modules, choose M here: the
+ modules will be called gspca_xxxx.
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
new file mode 100644
index 00000000000..e68a8965297
--- /dev/null
+++ b/drivers/media/video/gspca/Makefile
@@ -0,0 +1,29 @@
+obj-$(CONFIG_USB_GSPCA) += gspca_main.o \
+ gspca_conex.o gspca_etoms.o gspca_mars.o \
+ gspca_ov519.o gspca_pac207.o gspca_pac7311.o \
+ gspca_sonixb.o gspca_sonixj.o gspca_spca500.o gspca_spca501.o \
+ gspca_spca505.o gspca_spca506.o gspca_spca508.o gspca_spca561.o \
+ gspca_sunplus.o gspca_stk014.o gspca_t613.o gspca_tv8532.o \
+ gspca_vc032x.o gspca_zc3xx.o
+
+gspca_main-objs := gspca.o
+gspca_conex-objs := conex.o
+gspca_etoms-objs := etoms.o
+gspca_mars-objs := mars.o
+gspca_ov519-objs := ov519.o
+gspca_pac207-objs := pac207.o
+gspca_pac7311-objs := pac7311.o
+gspca_sonixb-objs := sonixb.o
+gspca_sonixj-objs := sonixj.o
+gspca_spca500-objs := spca500.o
+gspca_spca501-objs := spca501.o
+gspca_spca505-objs := spca505.o
+gspca_spca506-objs := spca506.o
+gspca_spca508-objs := spca508.o
+gspca_spca561-objs := spca561.o
+gspca_stk014-objs := stk014.o
+gspca_sunplus-objs := sunplus.o
+gspca_t613-objs := t613.o
+gspca_tv8532-objs := tv8532.o
+gspca_vc032x-objs := vc032x.o
+gspca_zc3xx-objs := zc3xx.o
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
new file mode 100644
index 00000000000..013d593b0c6
--- /dev/null
+++ b/drivers/media/video/gspca/conex.c
@@ -0,0 +1,1051 @@
+/*
+ * Connexant Cx11646 library
+ * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "conex"
+
+#include "gspca.h"
+#define CONEX_CAM 1 /* special JPEG header */
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA USB Conexant Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+
+ unsigned char qindex;
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 0xd4
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0x0a,
+ .maximum = 0x1f,
+ .step = 1,
+#define CONTRAST_DEF 0x0c
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 7,
+ .step = 1,
+#define COLOR_DEF 3
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/* the read bytes are found in gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+ __u16 index,
+ __u16 len)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (len > sizeof gspca_dev->usb_buf) {
+ err("reg_r: buffer overflow");
+ return;
+ }
+#endif
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ 0,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0,
+ index, gspca_dev->usb_buf, len,
+ 500);
+ PDEBUG(D_USBI, "reg read [%02x] -> %02x ..",
+ index, gspca_dev->usb_buf[0]);
+}
+
+/* the bytes to write are in gspca_dev->usb_buf */
+static void reg_w_val(struct gspca_dev *gspca_dev,
+ __u16 index,
+ __u8 val)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ gspca_dev->usb_buf[0] = val;
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0,
+ index, gspca_dev->usb_buf, 1, 500);
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+ __u16 index,
+ const __u8 *buffer,
+ __u16 len)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (len > sizeof gspca_dev->usb_buf) {
+ err("reg_w: buffer overflow");
+ return;
+ }
+ PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
+#endif
+ memcpy(gspca_dev->usb_buf, buffer, len);
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0,
+ index, gspca_dev->usb_buf, len, 500);
+}
+
+static const __u8 cx_sensor_init[][4] = {
+ {0x88, 0x11, 0x01, 0x01},
+ {0x88, 0x12, 0x70, 0x01},
+ {0x88, 0x0f, 0x00, 0x01},
+ {0x88, 0x05, 0x01, 0x01},
+ {}
+};
+
+static const __u8 cx11646_fw1[][3] = {
+ {0x00, 0x02, 0x00},
+ {0x01, 0x43, 0x00},
+ {0x02, 0xA7, 0x00},
+ {0x03, 0x8B, 0x01},
+ {0x04, 0xE9, 0x02},
+ {0x05, 0x08, 0x04},
+ {0x06, 0x08, 0x05},
+ {0x07, 0x07, 0x06},
+ {0x08, 0xE7, 0x06},
+ {0x09, 0xC6, 0x07},
+ {0x0A, 0x86, 0x08},
+ {0x0B, 0x46, 0x09},
+ {0x0C, 0x05, 0x0A},
+ {0x0D, 0xA5, 0x0A},
+ {0x0E, 0x45, 0x0B},
+ {0x0F, 0xE5, 0x0B},
+ {0x10, 0x85, 0x0C},
+ {0x11, 0x25, 0x0D},
+ {0x12, 0xC4, 0x0D},
+ {0x13, 0x45, 0x0E},
+ {0x14, 0xE4, 0x0E},
+ {0x15, 0x64, 0x0F},
+ {0x16, 0xE4, 0x0F},
+ {0x17, 0x64, 0x10},
+ {0x18, 0xE4, 0x10},
+ {0x19, 0x64, 0x11},
+ {0x1A, 0xE4, 0x11},
+ {0x1B, 0x64, 0x12},
+ {0x1C, 0xE3, 0x12},
+ {0x1D, 0x44, 0x13},
+ {0x1E, 0xC3, 0x13},
+ {0x1F, 0x24, 0x14},
+ {0x20, 0xA3, 0x14},
+ {0x21, 0x04, 0x15},
+ {0x22, 0x83, 0x15},
+ {0x23, 0xE3, 0x15},
+ {0x24, 0x43, 0x16},
+ {0x25, 0xA4, 0x16},
+ {0x26, 0x23, 0x17},
+ {0x27, 0x83, 0x17},
+ {0x28, 0xE3, 0x17},
+ {0x29, 0x43, 0x18},
+ {0x2A, 0xA3, 0x18},
+ {0x2B, 0x03, 0x19},
+ {0x2C, 0x63, 0x19},
+ {0x2D, 0xC3, 0x19},
+ {0x2E, 0x22, 0x1A},
+ {0x2F, 0x63, 0x1A},
+ {0x30, 0xC3, 0x1A},
+ {0x31, 0x23, 0x1B},
+ {0x32, 0x83, 0x1B},
+ {0x33, 0xE2, 0x1B},
+ {0x34, 0x23, 0x1C},
+ {0x35, 0x83, 0x1C},
+ {0x36, 0xE2, 0x1C},
+ {0x37, 0x23, 0x1D},
+ {0x38, 0x83, 0x1D},
+ {0x39, 0xE2, 0x1D},
+ {0x3A, 0x23, 0x1E},
+ {0x3B, 0x82, 0x1E},
+ {0x3C, 0xC3, 0x1E},
+ {0x3D, 0x22, 0x1F},
+ {0x3E, 0x63, 0x1F},
+ {0x3F, 0xC1, 0x1F},
+ {}
+};
+static void cx11646_fw(struct gspca_dev*gspca_dev)
+{
+ int i = 0;
+
+ reg_w_val(gspca_dev, 0x006a, 0x02);
+ while (cx11646_fw1[i][1]) {
+ reg_w(gspca_dev, 0x006b, cx11646_fw1[i], 3);
+ i++;
+ }
+ reg_w_val(gspca_dev, 0x006a, 0x00);
+}
+
+static const __u8 cxsensor[] = {
+ 0x88, 0x12, 0x70, 0x01,
+ 0x88, 0x0d, 0x02, 0x01,
+ 0x88, 0x0f, 0x00, 0x01,
+ 0x88, 0x03, 0x71, 0x01, 0x88, 0x04, 0x00, 0x01, /* 3 */
+ 0x88, 0x02, 0x10, 0x01,
+ 0x88, 0x00, 0xD4, 0x01, 0x88, 0x01, 0x01, 0x01, /* 5 */
+ 0x88, 0x0B, 0x00, 0x01,
+ 0x88, 0x0A, 0x0A, 0x01,
+ 0x88, 0x00, 0x08, 0x01, 0x88, 0x01, 0x00, 0x01, /* 8 */
+ 0x88, 0x05, 0x01, 0x01,
+ 0xA1, 0x18, 0x00, 0x01,
+ 0x00
+};
+
+static const __u8 reg20[] = { 0x10, 0x42, 0x81, 0x19, 0xd3, 0xff, 0xa7, 0xff };
+static const __u8 reg28[] = { 0x87, 0x00, 0x87, 0x00, 0x8f, 0xff, 0xea, 0xff };
+static const __u8 reg10[] = { 0xb1, 0xb1 };
+static const __u8 reg71a[] = { 0x08, 0x18, 0x0a, 0x1e }; /* 640 */
+static const __u8 reg71b[] = { 0x04, 0x0c, 0x05, 0x0f };
+ /* 352{0x04,0x0a,0x06,0x12}; //352{0x05,0x0e,0x06,0x11}; //352 */
+static const __u8 reg71c[] = { 0x02, 0x07, 0x03, 0x09 };
+ /* 320{0x04,0x0c,0x05,0x0f}; //320 */
+static const __u8 reg71d[] = { 0x02, 0x07, 0x03, 0x09 }; /* 176 */
+static const __u8 reg7b[] = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff };
+
+static void cx_sensor(struct gspca_dev*gspca_dev)
+{
+ int i = 0;
+ int length;
+ const __u8 *ptsensor = cxsensor;
+
+ reg_w(gspca_dev, 0x0020, reg20, 8);
+ reg_w(gspca_dev, 0x0028, reg28, 8);
+ reg_w(gspca_dev, 0x0010, reg10, 8);
+ reg_w_val(gspca_dev, 0x0092, 0x03);
+
+ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ case 0:
+ reg_w(gspca_dev, 0x0071, reg71a, 4);
+ break;
+ case 1:
+ reg_w(gspca_dev, 0x0071, reg71b, 4);
+ break;
+ default:
+/* case 2: */
+ reg_w(gspca_dev, 0x0071, reg71c, 4);
+ break;
+ case 3:
+ reg_w(gspca_dev, 0x0071, reg71d, 4);
+ break;
+ }
+ reg_w(gspca_dev, 0x007b, reg7b, 6);
+ reg_w_val(gspca_dev, 0x00f8, 0x00);
+ reg_w(gspca_dev, 0x0010, reg10, 8);
+ reg_w_val(gspca_dev, 0x0098, 0x41);
+ for (i = 0; i < 11; i++) {
+ if (i == 3 || i == 5 || i == 8)
+ length = 8;
+ else
+ length = 4;
+ reg_w(gspca_dev, 0x00e5, ptsensor, length);
+ if (length == 4)
+ reg_r(gspca_dev, 0x00e8, 1);
+ else
+ reg_r(gspca_dev, 0x00e8, length);
+ ptsensor += length;
+ }
+ reg_r(gspca_dev, 0x00e7, 8);
+}
+
+static const __u8 cx_inits_176[] = {
+ 0x33, 0x81, 0xB0, 0x00, 0x90, 0x00, 0x0A, 0x03, /* 176x144 */
+ 0x00, 0x03, 0x03, 0x03, 0x1B, 0x05, 0x30, 0x03,
+ 0x65, 0x15, 0x18, 0x25, 0x03, 0x25, 0x08, 0x30,
+ 0x3B, 0x25, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xDC, 0xFF, 0xEE, 0xFF, 0xC5, 0xFF, 0xBF, 0xFF,
+ 0xF7, 0xFF, 0x88, 0xFF, 0x66, 0x02, 0x28, 0x02,
+ 0x1E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const __u8 cx_inits_320[] = {
+ 0x7f, 0x7f, 0x40, 0x01, 0xf0, 0x00, 0x02, 0x01,
+ 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x02, 0x01,
+ 0x65, 0x45, 0xfa, 0x4c, 0x2c, 0xdf, 0xb9, 0x81,
+ 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+ 0xf5, 0xff, 0x6d, 0xff, 0xf6, 0x01, 0x43, 0x02,
+ 0xd3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const __u8 cx_inits_352[] = {
+ 0x2e, 0x7c, 0x60, 0x01, 0x20, 0x01, 0x05, 0x03,
+ 0x00, 0x06, 0x03, 0x06, 0x1b, 0x10, 0x05, 0x3b,
+ 0x30, 0x25, 0x18, 0x25, 0x08, 0x30, 0x03, 0x25,
+ 0x3b, 0x30, 0x25, 0x1b, 0x10, 0x05, 0x00, 0x00,
+ 0xe3, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+ 0xf5, 0xff, 0x6b, 0xff, 0xee, 0x01, 0x43, 0x02,
+ 0xe4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const __u8 cx_inits_640[] = {
+ 0x7e, 0x7e, 0x80, 0x02, 0xe0, 0x01, 0x01, 0x01,
+ 0x00, 0x02, 0x01, 0x02, 0x10, 0x30, 0x01, 0x01,
+ 0x65, 0x45, 0xf7, 0x52, 0x2c, 0xdf, 0xb9, 0x81,
+ 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+ 0xf6, 0xff, 0x7b, 0xff, 0x01, 0x02, 0x43, 0x02,
+ 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static void cx11646_initsize(struct gspca_dev *gspca_dev)
+{
+ const __u8 *cxinit;
+ static const __u8 reg12[] = { 0x08, 0x05, 0x07, 0x04, 0x24 };
+ static const __u8 reg17[] =
+ { 0x0a, 0x00, 0xf2, 0x01, 0x0f, 0x00, 0x97, 0x02 };
+
+ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ case 0:
+ cxinit = cx_inits_640;
+ break;
+ case 1:
+ cxinit = cx_inits_352;
+ break;
+ default:
+/* case 2: */
+ cxinit = cx_inits_320;
+ break;
+ case 3:
+ cxinit = cx_inits_176;
+ break;
+ }
+ reg_w_val(gspca_dev, 0x009a, 0x01);
+ reg_w_val(gspca_dev, 0x0010, 0x10);
+ reg_w(gspca_dev, 0x0012, reg12, 5);
+ reg_w(gspca_dev, 0x0017, reg17, 8);
+ reg_w_val(gspca_dev, 0x00c0, 0x00);
+ reg_w_val(gspca_dev, 0x00c1, 0x04);
+ reg_w_val(gspca_dev, 0x00c2, 0x04);
+
+ reg_w(gspca_dev, 0x0061, cxinit, 8);
+ cxinit += 8;
+ reg_w(gspca_dev, 0x00ca, cxinit, 8);
+ cxinit += 8;
+ reg_w(gspca_dev, 0x00d2, cxinit, 8);
+ cxinit += 8;
+ reg_w(gspca_dev, 0x00da, cxinit, 6);
+ cxinit += 8;
+ reg_w(gspca_dev, 0x0041, cxinit, 8);
+ cxinit += 8;
+ reg_w(gspca_dev, 0x0049, cxinit, 8);
+ cxinit += 8;
+ reg_w(gspca_dev, 0x0051, cxinit, 2);
+
+ reg_r(gspca_dev, 0x0010, 1);
+}
+
+static const __u8 cx_jpeg_init[][8] = {
+ {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x15}, /* 1 */
+ {0x0f, 0x10, 0x12, 0x10, 0x0d, 0x15, 0x12, 0x11},
+ {0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35, 0x22},
+ {0x20, 0x1d, 0x1d, 0x20, 0x41, 0x2e, 0x31, 0x26},
+ {0x35, 0x4d, 0x43, 0x51, 0x4f, 0x4b, 0x43, 0x4a},
+ {0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A, 0x73},
+ {0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73, 0x7D},
+ {0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95, 0xA0},
+ {0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83, 0x01},
+ {0x15, 0x0F, 0x10, 0x12, 0x10, 0x0D, 0x15, 0x12},
+ {0x11, 0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35},
+ {0x22, 0x20, 0x1D, 0x1D, 0x20, 0x41, 0x2E, 0x31},
+ {0x26, 0x35, 0x4D, 0x43, 0x51, 0x4F, 0x4B, 0x43},
+ {0x4A, 0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A},
+ {0x73, 0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73},
+ {0x7D, 0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95},
+ {0xA0, 0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83},
+ {0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05},
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02},
+ {0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A},
+ {0x0B, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01},
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05},
+ {0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00},
+ {0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05},
+ {0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01},
+ {0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21},
+ {0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22},
+ {0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23},
+ {0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24},
+ {0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17},
+ {0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29},
+ {0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A},
+ {0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A},
+ {0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A},
+ {0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A},
+ {0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A},
+ {0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A},
+ {0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99},
+ {0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8},
+ {0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7},
+ {0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6},
+ {0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5},
+ {0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3},
+ {0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1},
+ {0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9},
+ {0xFA, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04},
+ {0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01},
+ {0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04},
+ {0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07},
+ {0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14},
+ {0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33},
+ {0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16},
+ {0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19},
+ {0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36},
+ {0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46},
+ {0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56},
+ {0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66},
+ {0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76},
+ {0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85},
+ {0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94},
+ {0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3},
+ {0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2},
+ {0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA},
+ {0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9},
+ {0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8},
+ {0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7},
+ {0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6},
+ {0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0x20, 0x00, 0x1F},
+ {0x02, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x11, 0x00, 0x11, 0x22, 0x00, 0x22},
+ {0x22, 0x11, 0x22, 0x22, 0x11, 0x33, 0x33, 0x11},
+ {0x44, 0x66, 0x22, 0x55, 0x66, 0xFF, 0xDD, 0x00},
+ {0x04, 0x00, 0x14, 0xFF, 0xC0, 0x00, 0x11, 0x08},
+ {0x00, 0xF0, 0x01, 0x40, 0x03, 0x00, 0x21, 0x00},
+ {0x01, 0x11, 0x01, 0x02, 0x11, 0x01, 0xFF, 0xDA},
+ {0x00, 0x0C, 0x03, 0x00, 0x00, 0x01, 0x11, 0x02},
+ {0x11, 0x00, 0x3F, 0x00, 0xFF, 0xD9, 0x00, 0x00} /* 79 */
+};
+
+
+static const __u8 cxjpeg_640[][8] = {
+ {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x10}, /* 1 */
+ {0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d},
+ {0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a},
+ {0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d},
+ {0x28, 0x3a, 0x33, 0x3D, 0x3C, 0x39, 0x33, 0x38},
+ {0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44, 0x57},
+ {0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57, 0x5F},
+ {0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71, 0x79},
+ {0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63, 0x01},
+ {0x10, 0x0B, 0x0C, 0x0E, 0x0C, 0x0A, 0x10, 0x0E},
+ {0x0D, 0x0E, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28},
+ {0x1A, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25},
+ {0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39, 0x33},
+ {0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44},
+ {0x57, 0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57},
+ {0x5F, 0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71},
+ {0x79, 0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63},
+ {0xFF, 0x20, 0x00, 0x1F, 0x00, 0x83, 0x00, 0x00},
+ {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+ {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+ {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+ {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x28, 0xFF},
+ {0xC0, 0x00, 0x11, 0x08, 0x01, 0xE0, 0x02, 0x80},
+ {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+ {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+ {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+ {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 27 */
+};
+static const __u8 cxjpeg_352[][8] = {
+ {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d},
+ {0x09, 0x09, 0x0b, 0x09, 0x08, 0x0D, 0x0b, 0x0a},
+ {0x0b, 0x0e, 0x0d, 0x0d, 0x0f, 0x13, 0x1f, 0x14},
+ {0x13, 0x11, 0x11, 0x13, 0x26, 0x1b, 0x1d, 0x17},
+ {0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C},
+ {0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44},
+ {0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A},
+ {0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F},
+ {0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01},
+ {0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B},
+ {0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F},
+ {0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D},
+ {0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28},
+ {0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35},
+ {0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44},
+ {0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58},
+ {0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D},
+ {0xFF, 0x20, 0x00, 0x1F, 0x01, 0x83, 0x00, 0x00},
+ {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+ {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+ {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+ {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x16, 0xFF},
+ {0xC0, 0x00, 0x11, 0x08, 0x01, 0x20, 0x01, 0x60},
+ {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+ {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+ {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+ {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+static const __u8 cxjpeg_320[][8] = {
+ {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x05},
+ {0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04},
+ {0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08},
+ {0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, 0x0b, 0x09},
+ {0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0f, 0x11},
+ {0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14, 0x1A},
+ {0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D},
+ {0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22, 0x24},
+ {0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0x01},
+ {0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04},
+ {0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C},
+ {0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B, 0x0B},
+ {0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F},
+ {0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14},
+ {0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A},
+ {0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22},
+ {0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E},
+ {0xFF, 0x20, 0x00, 0x1F, 0x02, 0x0C, 0x00, 0x00},
+ {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+ {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+ {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+ {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x14, 0xFF},
+ {0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, 0x40},
+ {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+ {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+ {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+ {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 27 */
+};
+static const __u8 cxjpeg_176[][8] = {
+ {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d},
+ {0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B, 0x0A},
+ {0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F, 0x14},
+ {0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D, 0x17},
+ {0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C},
+ {0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44},
+ {0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A},
+ {0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F},
+ {0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01},
+ {0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B},
+ {0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F},
+ {0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D},
+ {0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28},
+ {0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35},
+ {0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44},
+ {0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58},
+ {0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D},
+ {0xFF, 0x20, 0x00, 0x1F, 0x03, 0xA1, 0x00, 0x00},
+ {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+ {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+ {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+ {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x0B, 0xFF},
+ {0xC0, 0x00, 0x11, 0x08, 0x00, 0x90, 0x00, 0xB0},
+ {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+ {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+ {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+ {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+/* 640 take with the zcx30x part */
+static const __u8 cxjpeg_qtable[][8] = {
+ {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x08},
+ {0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, 0x07},
+ {0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0a},
+ {0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13, 0x0f},
+ {0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, 0x1c},
+ {0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22, 0x2c},
+ {0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30},
+ {0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39, 0x3d},
+ {0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0x01},
+ {0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0a},
+ {0x0a, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32},
+ {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+ {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+ {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+ {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+ {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+ {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+ {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 18 */
+};
+
+
+static void cx11646_jpegInit(struct gspca_dev*gspca_dev)
+{
+ int i;
+ int length;
+
+ reg_w_val(gspca_dev, 0x00c0, 0x01);
+ reg_w_val(gspca_dev, 0x00c3, 0x00);
+ reg_w_val(gspca_dev, 0x00c0, 0x00);
+ reg_r(gspca_dev, 0x0001, 1);
+ length = 8;
+ for (i = 0; i < 79; i++) {
+ if (i == 78)
+ length = 6;
+ reg_w(gspca_dev, 0x0008, cx_jpeg_init[i], length);
+ }
+ reg_r(gspca_dev, 0x0002, 1);
+ reg_w_val(gspca_dev, 0x0055, 0x14);
+}
+
+static const __u8 reg12[] = { 0x0a, 0x05, 0x07, 0x04, 0x19 };
+static const __u8 regE5_8[] =
+ { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
+static const __u8 regE5a[] = { 0x88, 0x0a, 0x0c, 0x01 };
+static const __u8 regE5b[] = { 0x88, 0x0b, 0x12, 0x01 };
+static const __u8 regE5c[] = { 0x88, 0x05, 0x01, 0x01 };
+static const __u8 reg51[] = { 0x77, 0x03 };
+#define reg70 0x03
+
+static void cx11646_jpeg(struct gspca_dev*gspca_dev)
+{
+ int i;
+ int length;
+ __u8 Reg55;
+ int retry;
+
+ reg_w_val(gspca_dev, 0x00c0, 0x01);
+ reg_w_val(gspca_dev, 0x00c3, 0x00);
+ reg_w_val(gspca_dev, 0x00c0, 0x00);
+ reg_r(gspca_dev, 0x0001, 1);
+ length = 8;
+ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ case 0:
+ for (i = 0; i < 27; i++) {
+ if (i == 26)
+ length = 2;
+ reg_w(gspca_dev, 0x0008, cxjpeg_640[i], length);
+ }
+ Reg55 = 0x28;
+ break;
+ case 1:
+ for (i = 0; i < 27; i++) {
+ if (i == 26)
+ length = 2;
+ reg_w(gspca_dev, 0x0008, cxjpeg_352[i], length);
+ }
+ Reg55 = 0x16;
+ break;
+ default:
+/* case 2: */
+ for (i = 0; i < 27; i++) {
+ if (i == 26)
+ length = 2;
+ reg_w(gspca_dev, 0x0008, cxjpeg_320[i], length);
+ }
+ Reg55 = 0x14;
+ break;
+ case 3:
+ for (i = 0; i < 27; i++) {
+ if (i == 26)
+ length = 2;
+ reg_w(gspca_dev, 0x0008, cxjpeg_176[i], length);
+ }
+ Reg55 = 0x0B;
+ break;
+ }
+
+ reg_r(gspca_dev, 0x0002, 1);
+ reg_w_val(gspca_dev, 0x0055, Reg55);
+ reg_r(gspca_dev, 0x0002, 1);
+ reg_w(gspca_dev, 0x0010, reg10, 2);
+ reg_w_val(gspca_dev, 0x0054, 0x02);
+ reg_w_val(gspca_dev, 0x0054, 0x01);
+ reg_w_val(gspca_dev, 0x0000, 0x94);
+ reg_w_val(gspca_dev, 0x0053, 0xc0);
+ reg_w_val(gspca_dev, 0x00fc, 0xe1);
+ reg_w_val(gspca_dev, 0x0000, 0x00);
+ /* wait for completion */
+ retry = 50;
+ while (retry--) {
+ reg_r(gspca_dev, 0x0002, 1);
+ /* 0x07 until 0x00 */
+ if (gspca_dev->usb_buf[0] == 0x00)
+ break;
+ reg_w_val(gspca_dev, 0x0053, 0x00);
+ }
+ if (retry == 0)
+ PDEBUG(D_ERR, "Damned Errors sending jpeg Table");
+ /* send the qtable now */
+ reg_r(gspca_dev, 0x0001, 1); /* -> 0x18 */
+ length = 8;
+ for (i = 0; i < 18; i++) {
+ if (i == 17)
+ length = 2;
+ reg_w(gspca_dev, 0x0008, cxjpeg_qtable[i], length);
+
+ }
+ reg_r(gspca_dev, 0x0002, 1); /* 0x00 */
+ reg_r(gspca_dev, 0x0053, 1); /* 0x00 */
+ reg_w_val(gspca_dev, 0x0054, 0x02);
+ reg_w_val(gspca_dev, 0x0054, 0x01);
+ reg_w_val(gspca_dev, 0x0000, 0x94);
+ reg_w_val(gspca_dev, 0x0053, 0xc0);
+
+ reg_r(gspca_dev, 0x0038, 1); /* 0x40 */
+ reg_r(gspca_dev, 0x0038, 1); /* 0x40 */
+ reg_r(gspca_dev, 0x001f, 1); /* 0x38 */
+ reg_w(gspca_dev, 0x0012, reg12, 5);
+ reg_w(gspca_dev, 0x00e5, regE5_8, 8);
+ reg_r(gspca_dev, 0x00e8, 8);
+ reg_w(gspca_dev, 0x00e5, regE5a, 4);
+ reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */
+ reg_w_val(gspca_dev, 0x009a, 0x01);
+ reg_w(gspca_dev, 0x00e5, regE5b, 4);
+ reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */
+ reg_w(gspca_dev, 0x00e5, regE5c, 4);
+ reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */
+
+ reg_w(gspca_dev, 0x0051, reg51, 2);
+ reg_w(gspca_dev, 0x0010, reg10, 2);
+ reg_w_val(gspca_dev, 0x0070, reg70);
+}
+
+static void cx11646_init1(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+
+ reg_w_val(gspca_dev, 0x0010, 0x00);
+ reg_w_val(gspca_dev, 0x0053, 0x00);
+ reg_w_val(gspca_dev, 0x0052, 0x00);
+ reg_w_val(gspca_dev, 0x009b, 0x2f);
+ reg_w_val(gspca_dev, 0x009c, 0x10);
+ reg_r(gspca_dev, 0x0098, 1);
+ reg_w_val(gspca_dev, 0x0098, 0x40);
+ reg_r(gspca_dev, 0x0099, 1);
+ reg_w_val(gspca_dev, 0x0099, 0x07);
+ reg_w_val(gspca_dev, 0x0039, 0x40);
+ reg_w_val(gspca_dev, 0x003c, 0xff);
+ reg_w_val(gspca_dev, 0x003f, 0x1f);
+ reg_w_val(gspca_dev, 0x003d, 0x40);
+/* reg_w_val(gspca_dev, 0x003d, 0x60); */
+ reg_r(gspca_dev, 0x0099, 1); /* ->0x07 */
+
+ while (cx_sensor_init[i][0]) {
+ reg_w_val(gspca_dev, 0x00e5, cx_sensor_init[i][0]);
+ reg_r(gspca_dev, 0x00e8, 1); /* -> 0x00 */
+ if (i == 1) {
+ reg_w_val(gspca_dev, 0x00ed, 0x01);
+ reg_r(gspca_dev, 0x00ed, 1); /* -> 0x01 */
+ }
+ i++;
+ }
+ reg_w_val(gspca_dev, 0x00c3, 0x00);
+}
+
+/* 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;
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+
+ sd->qindex = 0; /* set the quantization */
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ cx11646_init1(gspca_dev);
+ cx11646_initsize(gspca_dev);
+ cx11646_fw(gspca_dev);
+ cx_sensor(gspca_dev);
+ cx11646_jpegInit(gspca_dev);
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ cx11646_initsize(gspca_dev);
+ cx11646_fw(gspca_dev);
+ cx_sensor(gspca_dev);
+ cx11646_jpeg(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ int retry = 50;
+
+ reg_w_val(gspca_dev, 0x0000, 0x00);
+ reg_r(gspca_dev, 0x0002, 1);
+ reg_w_val(gspca_dev, 0x0053, 0x00);
+
+ while (retry--) {
+/* reg_r(gspca_dev, 0x0002, 1);*/
+ reg_r(gspca_dev, 0x0053, 1);
+ if (gspca_dev->usb_buf[0] == 0)
+ break;
+ }
+ reg_w_val(gspca_dev, 0x0000, 0x00);
+ reg_r(gspca_dev, 0x0002, 1);
+
+ reg_w_val(gspca_dev, 0x0010, 0x00);
+ reg_r(gspca_dev, 0x0033, 1);
+ reg_w_val(gspca_dev, 0x00fc, 0xe0);
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ if (data[0] == 0xff && data[1] == 0xd8) {
+
+ /* start of frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+
+ /* put the JPEG header in the new frame */
+ jpeg_put_header(gspca_dev, frame,
+ ((struct sd *) gspca_dev)->qindex,
+ 0x22);
+ data += 2;
+ len -= 2;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void setbrightness(struct gspca_dev*gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 regE5cbx[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
+ __u8 reg51c[2];
+ __u8 bright;
+ __u8 colors;
+
+ bright = sd->brightness;
+ regE5cbx[2] = bright;
+ reg_w(gspca_dev, 0x00e5, regE5cbx, 8);
+ reg_r(gspca_dev, 0x00e8, 8);
+ reg_w(gspca_dev, 0x00e5, regE5c, 4);
+ reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */
+
+ colors = sd->colors;
+ reg51c[0] = 0x77;
+ reg51c[1] = colors;
+ reg_w(gspca_dev, 0x0051, reg51c, 2);
+ reg_w(gspca_dev, 0x0010, reg10, 2);
+ reg_w_val(gspca_dev, 0x0070, reg70);
+}
+
+static void setcontrast(struct gspca_dev*gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 regE5acx[] = { 0x88, 0x0a, 0x0c, 0x01 }; /* seem MSB */
+/* __u8 regE5bcx[] = { 0x88, 0x0b, 0x12, 0x01}; * LSB */
+ __u8 reg51c[2];
+
+ regE5acx[2] = sd->contrast;
+ reg_w(gspca_dev, 0x00e5, regE5acx, 4);
+ reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */
+ reg51c[0] = 0x77;
+ reg51c[1] = sd->colors;
+ reg_w(gspca_dev, 0x0051, reg51c, 2);
+ reg_w(gspca_dev, 0x0010, reg10, 2);
+ reg_w_val(gspca_dev, 0x0070, reg70);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming) {
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ }
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->colors;
+ return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0572, 0x0041), DVNM("Creative Notebook cx11646")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
new file mode 100644
index 00000000000..8ab4ea7201a
--- /dev/null
+++ b/drivers/media/video/gspca/etoms.c
@@ -0,0 +1,956 @@
+/*
+ * Etoms Et61x151 GPL Linux driver by Michel Xhaard (09/09/2004)
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "etoms"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("Etoms USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char autogain;
+
+ char sensor;
+#define SENSOR_PAS106 0
+#define SENSOR_TAS5130CXX 1
+ signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 1,
+ .maximum = 127,
+ .step = 1,
+#define BRIGHTNESS_DEF 63
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define CONTRAST_DEF 127
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 15,
+ .step = 1,
+#define COLOR_DEF 7
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+/* {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0}, */
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+#define ETOMS_ALT_SIZE_1000 12
+
+#define ET_GPIO_DIR_CTRL 0x04 /* Control IO bit[0..5] (0 in 1 out) */
+#define ET_GPIO_OUT 0x05 /* Only IO data */
+#define ET_GPIO_IN 0x06 /* Read Only IO data */
+#define ET_RESET_ALL 0x03
+#define ET_ClCK 0x01
+#define ET_CTRL 0x02 /* enable i2c OutClck Powerdown mode */
+
+#define ET_COMP 0x12 /* Compression register */
+#define ET_MAXQt 0x13
+#define ET_MINQt 0x14
+#define ET_COMP_VAL0 0x02
+#define ET_COMP_VAL1 0x03
+
+#define ET_REG1d 0x1d
+#define ET_REG1e 0x1e
+#define ET_REG1f 0x1f
+#define ET_REG20 0x20
+#define ET_REG21 0x21
+#define ET_REG22 0x22
+#define ET_REG23 0x23
+#define ET_REG24 0x24
+#define ET_REG25 0x25
+/* base registers for luma calculation */
+#define ET_LUMA_CENTER 0x39
+
+#define ET_G_RED 0x4d
+#define ET_G_GREEN1 0x4e
+#define ET_G_BLUE 0x4f
+#define ET_G_GREEN2 0x50
+#define ET_G_GR_H 0x51
+#define ET_G_GB_H 0x52
+
+#define ET_O_RED 0x34
+#define ET_O_GREEN1 0x35
+#define ET_O_BLUE 0x36
+#define ET_O_GREEN2 0x37
+
+#define ET_SYNCHRO 0x68
+#define ET_STARTX 0x69
+#define ET_STARTY 0x6a
+#define ET_WIDTH_LOW 0x6b
+#define ET_HEIGTH_LOW 0x6c
+#define ET_W_H_HEIGTH 0x6d
+
+#define ET_REG6e 0x6e /* OBW */
+#define ET_REG6f 0x6f /* OBW */
+#define ET_REG70 0x70 /* OBW_AWB */
+#define ET_REG71 0x71 /* OBW_AWB */
+#define ET_REG72 0x72 /* OBW_AWB */
+#define ET_REG73 0x73 /* Clkdelay ns */
+#define ET_REG74 0x74 /* test pattern */
+#define ET_REG75 0x75 /* test pattern */
+
+#define ET_I2C_CLK 0x8c
+#define ET_PXL_CLK 0x60
+
+#define ET_I2C_BASE 0x89
+#define ET_I2C_COUNT 0x8a
+#define ET_I2C_PREFETCH 0x8b
+#define ET_I2C_REG 0x88
+#define ET_I2C_DATA7 0x87
+#define ET_I2C_DATA6 0x86
+#define ET_I2C_DATA5 0x85
+#define ET_I2C_DATA4 0x84
+#define ET_I2C_DATA3 0x83
+#define ET_I2C_DATA2 0x82
+#define ET_I2C_DATA1 0x81
+#define ET_I2C_DATA0 0x80
+
+#define PAS106_REG2 0x02 /* pxlClk = systemClk/(reg2) */
+#define PAS106_REG3 0x03 /* line/frame H [11..4] */
+#define PAS106_REG4 0x04 /* line/frame L [3..0] */
+#define PAS106_REG5 0x05 /* exposure time line offset(default 5) */
+#define PAS106_REG6 0x06 /* exposure time pixel offset(default 6) */
+#define PAS106_REG7 0x07 /* signbit Dac (default 0) */
+#define PAS106_REG9 0x09
+#define PAS106_REG0e 0x0e /* global gain [4..0](default 0x0e) */
+#define PAS106_REG13 0x13 /* end i2c write */
+
+static const __u8 GainRGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
+
+static const __u8 I2c2[] = { 0x08, 0x08, 0x08, 0x08, 0x0d };
+
+static const __u8 I2c3[] = { 0x12, 0x05 };
+
+static const __u8 I2c4[] = { 0x41, 0x08 };
+
+/* read 'len' bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+ __u16 index,
+ __u16 len)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (len > sizeof gspca_dev->usb_buf) {
+ err("reg_r: buffer overflow");
+ return;
+ }
+#endif
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ 0,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0,
+ index, gspca_dev->usb_buf, len, 500);
+ PDEBUG(D_USBI, "reg read [%02x] -> %02x ..",
+ index, gspca_dev->usb_buf[0]);
+}
+
+static void reg_w_val(struct gspca_dev *gspca_dev,
+ __u16 index,
+ __u8 val)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ gspca_dev->usb_buf[0] = val;
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0,
+ index, gspca_dev->usb_buf, 1, 500);
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+ __u16 index,
+ const __u8 *buffer,
+ __u16 len)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (len > sizeof gspca_dev->usb_buf) {
+ err("reg_w: buffer overflow");
+ return;
+ }
+ PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
+#endif
+ memcpy(gspca_dev->usb_buf, buffer, len);
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0, index, gspca_dev->usb_buf, len, 500);
+}
+
+static int i2c_w(struct gspca_dev *gspca_dev,
+ __u8 reg,
+ const __u8 *buffer,
+ int len, __u8 mode)
+{
+ /* buffer should be [D0..D7] */
+ __u8 ptchcount;
+
+ /* set the base address */
+ reg_w_val(gspca_dev, ET_I2C_BASE, 0x40);
+ /* sensor base for the pas106 */
+ /* set count and prefetch */
+ ptchcount = ((len & 0x07) << 4) | (mode & 0x03);
+ reg_w_val(gspca_dev, ET_I2C_COUNT, ptchcount);
+ /* set the register base */
+ reg_w_val(gspca_dev, ET_I2C_REG, reg);
+ while (--len >= 0)
+ reg_w_val(gspca_dev, ET_I2C_DATA0 + len, buffer[len]);
+ return 0;
+}
+
+static int i2c_r(struct gspca_dev *gspca_dev,
+ __u8 reg)
+{
+ /* set the base address */
+ reg_w_val(gspca_dev, ET_I2C_BASE, 0x40);
+ /* sensor base for the pas106 */
+ /* set count and prefetch (cnd: 4 bits - mode: 4 bits) */
+ reg_w_val(gspca_dev, ET_I2C_COUNT, 0x11);
+ reg_w_val(gspca_dev, ET_I2C_REG, reg); /* set the register base */
+ reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x02); /* prefetch */
+ reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x00);
+ reg_r(gspca_dev, ET_I2C_DATA0, 1); /* read one byte */
+ return 0;
+}
+
+static int Et_WaitStatus(struct gspca_dev *gspca_dev)
+{
+ int retry = 10;
+
+ while (retry--) {
+ reg_r(gspca_dev, ET_ClCK, 1);
+ if (gspca_dev->usb_buf[0] != 0)
+ return 1;
+ }
+ return 0;
+}
+
+static int et_video(struct gspca_dev *gspca_dev,
+ int on)
+{
+ int ret;
+
+ reg_w_val(gspca_dev, ET_GPIO_OUT,
+ on ? 0x10 /* startvideo - set Bit5 */
+ : 0); /* stopvideo */
+ ret = Et_WaitStatus(gspca_dev);
+ if (ret != 0)
+ PDEBUG(D_ERR, "timeout video on/off");
+ return ret;
+}
+
+static void Et_init2(struct gspca_dev *gspca_dev)
+{
+ __u8 value;
+ static const __u8 FormLine[] = { 0x84, 0x03, 0x14, 0xf4, 0x01, 0x05 };
+
+ PDEBUG(D_STREAM, "Open Init2 ET");
+ reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 0x2f);
+ reg_w_val(gspca_dev, ET_GPIO_OUT, 0x10);
+ reg_r(gspca_dev, ET_GPIO_IN, 1);
+ reg_w_val(gspca_dev, ET_ClCK, 0x14); /* 0x14 // 0x16 enabled pattern */
+ reg_w_val(gspca_dev, ET_CTRL, 0x1b);
+
+ /* compression et subsampling */
+ if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
+ value = ET_COMP_VAL1; /* 320 */
+ else
+ value = ET_COMP_VAL0; /* 640 */
+ reg_w_val(gspca_dev, ET_COMP, value);
+ reg_w_val(gspca_dev, ET_MAXQt, 0x1f);
+ reg_w_val(gspca_dev, ET_MINQt, 0x04);
+ /* undocumented registers */
+ reg_w_val(gspca_dev, ET_REG1d, 0xff);
+ reg_w_val(gspca_dev, ET_REG1e, 0xff);
+ reg_w_val(gspca_dev, ET_REG1f, 0xff);
+ reg_w_val(gspca_dev, ET_REG20, 0x35);
+ reg_w_val(gspca_dev, ET_REG21, 0x01);
+ reg_w_val(gspca_dev, ET_REG22, 0x00);
+ reg_w_val(gspca_dev, ET_REG23, 0xff);
+ reg_w_val(gspca_dev, ET_REG24, 0xff);
+ reg_w_val(gspca_dev, ET_REG25, 0x0f);
+ /* colors setting */
+ reg_w_val(gspca_dev, 0x30, 0x11); /* 0x30 */
+ reg_w_val(gspca_dev, 0x31, 0x40);
+ reg_w_val(gspca_dev, 0x32, 0x00);
+ reg_w_val(gspca_dev, ET_O_RED, 0x00); /* 0x34 */
+ reg_w_val(gspca_dev, ET_O_GREEN1, 0x00);
+ reg_w_val(gspca_dev, ET_O_BLUE, 0x00);
+ reg_w_val(gspca_dev, ET_O_GREEN2, 0x00);
+ /*************/
+ reg_w_val(gspca_dev, ET_G_RED, 0x80); /* 0x4d */
+ reg_w_val(gspca_dev, ET_G_GREEN1, 0x80);
+ reg_w_val(gspca_dev, ET_G_BLUE, 0x80);
+ reg_w_val(gspca_dev, ET_G_GREEN2, 0x80);
+ reg_w_val(gspca_dev, ET_G_GR_H, 0x00);
+ reg_w_val(gspca_dev, ET_G_GB_H, 0x00); /* 0x52 */
+ /* Window control registers */
+ reg_w_val(gspca_dev, 0x61, 0x80); /* use cmc_out */
+ reg_w_val(gspca_dev, 0x62, 0x02);
+ reg_w_val(gspca_dev, 0x63, 0x03);
+ reg_w_val(gspca_dev, 0x64, 0x14);
+ reg_w_val(gspca_dev, 0x65, 0x0e);
+ reg_w_val(gspca_dev, 0x66, 0x02);
+ reg_w_val(gspca_dev, 0x67, 0x02);
+
+ /**************************************/
+ reg_w_val(gspca_dev, ET_SYNCHRO, 0x8f); /* 0x68 */
+ reg_w_val(gspca_dev, ET_STARTX, 0x69); /* 0x6a //0x69 */
+ reg_w_val(gspca_dev, ET_STARTY, 0x0d); /* 0x0d //0x0c */
+ reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x80);
+ reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0xe0);
+ reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x60); /* 6d */
+ reg_w_val(gspca_dev, ET_REG6e, 0x86);
+ reg_w_val(gspca_dev, ET_REG6f, 0x01);
+ reg_w_val(gspca_dev, ET_REG70, 0x26);
+ reg_w_val(gspca_dev, ET_REG71, 0x7a);
+ reg_w_val(gspca_dev, ET_REG72, 0x01);
+ /* Clock Pattern registers ***************** */
+ reg_w_val(gspca_dev, ET_REG73, 0x00);
+ reg_w_val(gspca_dev, ET_REG74, 0x18); /* 0x28 */
+ reg_w_val(gspca_dev, ET_REG75, 0x0f); /* 0x01 */
+ /**********************************************/
+ reg_w_val(gspca_dev, 0x8a, 0x20);
+ reg_w_val(gspca_dev, 0x8d, 0x0f);
+ reg_w_val(gspca_dev, 0x8e, 0x08);
+ /**************************************/
+ reg_w_val(gspca_dev, 0x03, 0x08);
+ reg_w_val(gspca_dev, ET_PXL_CLK, 0x03);
+ reg_w_val(gspca_dev, 0x81, 0xff);
+ reg_w_val(gspca_dev, 0x80, 0x00);
+ reg_w_val(gspca_dev, 0x81, 0xff);
+ reg_w_val(gspca_dev, 0x80, 0x20);
+ reg_w_val(gspca_dev, 0x03, 0x01);
+ reg_w_val(gspca_dev, 0x03, 0x00);
+ reg_w_val(gspca_dev, 0x03, 0x08);
+ /********************************************/
+
+/* reg_r(gspca_dev, ET_I2C_BASE, 1);
+ always 0x40 as the pas106 ??? */
+ /* set the sensor */
+ if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
+ value = 0x04; /* 320 */
+ else /* 640 */
+ value = 0x1e; /* 0x17 * setting PixelClock
+ * 0x03 mean 24/(3+1) = 6 Mhz
+ * 0x05 -> 24/(5+1) = 4 Mhz
+ * 0x0b -> 24/(11+1) = 2 Mhz
+ * 0x17 -> 24/(23+1) = 1 Mhz
+ */
+ reg_w_val(gspca_dev, ET_PXL_CLK, value);
+ /* now set by fifo the FormatLine setting */
+ reg_w(gspca_dev, 0x62, FormLine, 6);
+
+ /* set exposure times [ 0..0x78] 0->longvalue 0x78->shortvalue */
+ reg_w_val(gspca_dev, 0x81, 0x47); /* 0x47; */
+ reg_w_val(gspca_dev, 0x80, 0x40); /* 0x40; */
+ /* Pedro change */
+ /* Brightness change Brith+ decrease value */
+ /* Brigth- increase value */
+ /* original value = 0x70; */
+ reg_w_val(gspca_dev, 0x81, 0x30); /* 0x20; - set brightness */
+ reg_w_val(gspca_dev, 0x80, 0x20); /* 0x20; */
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 I2cc[] = { 0x05, 0x02, 0x02, 0x05, 0x0d };
+ __u8 i2cflags = 0x01;
+ /* __u8 green = 0; */
+ __u8 colors = sd->colors;
+
+ I2cc[3] = colors; /* red */
+ I2cc[0] = 15 - colors; /* blue */
+ /* green = 15 - ((((7*I2cc[0]) >> 2 ) + I2cc[3]) >> 1); */
+ /* I2cc[1] = I2cc[2] = green; */
+ if (sd->sensor == SENSOR_PAS106) {
+ i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3);
+ i2c_w(gspca_dev, PAS106_REG9, I2cc, sizeof I2cc, 1);
+ }
+/* PDEBUG(D_CONF , "Etoms red %d blue %d green %d",
+ I2cc[3], I2cc[0], green); */
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PAS106) {
+/* i2c_r(gspca_dev, PAS106_REG9); * blue */
+ i2c_r(gspca_dev, PAS106_REG9 + 3); /* red */
+ sd->colors = gspca_dev->usb_buf[0] & 0x0f;
+ }
+}
+
+static void Et_init1(struct gspca_dev *gspca_dev)
+{
+ __u8 value;
+/* __u8 I2c0 [] = {0x0a, 0x12, 0x05, 0x22, 0xac, 0x00, 0x01, 0x00}; */
+ __u8 I2c0[] = { 0x0a, 0x12, 0x05, 0x6d, 0xcd, 0x00, 0x01, 0x00 };
+ /* try 1/120 0x6d 0xcd 0x40 */
+/* __u8 I2c0 [] = {0x0a, 0x12, 0x05, 0xfe, 0xfe, 0xc0, 0x01, 0x00};
+ * 1/60000 hmm ?? */
+
+ PDEBUG(D_STREAM, "Open Init1 ET");
+ reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 7);
+ reg_r(gspca_dev, ET_GPIO_IN, 1);
+ reg_w_val(gspca_dev, ET_RESET_ALL, 1);
+ reg_w_val(gspca_dev, ET_RESET_ALL, 0);
+ reg_w_val(gspca_dev, ET_ClCK, 0x10);
+ reg_w_val(gspca_dev, ET_CTRL, 0x19);
+ /* compression et subsampling */
+ if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
+ value = ET_COMP_VAL1;
+ else
+ value = ET_COMP_VAL0;
+ PDEBUG(D_STREAM, "Open mode %d Compression %d",
+ gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv,
+ value);
+ reg_w_val(gspca_dev, ET_COMP, value);
+ reg_w_val(gspca_dev, ET_MAXQt, 0x1d);
+ reg_w_val(gspca_dev, ET_MINQt, 0x02);
+ /* undocumented registers */
+ reg_w_val(gspca_dev, ET_REG1d, 0xff);
+ reg_w_val(gspca_dev, ET_REG1e, 0xff);
+ reg_w_val(gspca_dev, ET_REG1f, 0xff);
+ reg_w_val(gspca_dev, ET_REG20, 0x35);
+ reg_w_val(gspca_dev, ET_REG21, 0x01);
+ reg_w_val(gspca_dev, ET_REG22, 0x00);
+ reg_w_val(gspca_dev, ET_REG23, 0xf7);
+ reg_w_val(gspca_dev, ET_REG24, 0xff);
+ reg_w_val(gspca_dev, ET_REG25, 0x07);
+ /* colors setting */
+ reg_w_val(gspca_dev, ET_G_RED, 0x80);
+ reg_w_val(gspca_dev, ET_G_GREEN1, 0x80);
+ reg_w_val(gspca_dev, ET_G_BLUE, 0x80);
+ reg_w_val(gspca_dev, ET_G_GREEN2, 0x80);
+ reg_w_val(gspca_dev, ET_G_GR_H, 0x00);
+ reg_w_val(gspca_dev, ET_G_GB_H, 0x00);
+ /* Window control registers */
+ reg_w_val(gspca_dev, ET_SYNCHRO, 0xf0);
+ reg_w_val(gspca_dev, ET_STARTX, 0x56); /* 0x56 */
+ reg_w_val(gspca_dev, ET_STARTY, 0x05); /* 0x04 */
+ reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x60);
+ reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0x20);
+ reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x50);
+ reg_w_val(gspca_dev, ET_REG6e, 0x86);
+ reg_w_val(gspca_dev, ET_REG6f, 0x01);
+ reg_w_val(gspca_dev, ET_REG70, 0x86);
+ reg_w_val(gspca_dev, ET_REG71, 0x14);
+ reg_w_val(gspca_dev, ET_REG72, 0x00);
+ /* Clock Pattern registers */
+ reg_w_val(gspca_dev, ET_REG73, 0x00);
+ reg_w_val(gspca_dev, ET_REG74, 0x00);
+ reg_w_val(gspca_dev, ET_REG75, 0x0a);
+ reg_w_val(gspca_dev, ET_I2C_CLK, 0x04);
+ reg_w_val(gspca_dev, ET_PXL_CLK, 0x01);
+ /* set the sensor */
+ if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ I2c0[0] = 0x06;
+ i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1);
+ i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1);
+ value = 0x06;
+ i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1);
+ i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1);
+ /* value = 0x1f; */
+ value = 0x04;
+ i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1);
+ } else {
+ I2c0[0] = 0x0a;
+
+ i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1);
+ i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1);
+ value = 0x0a;
+ i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1);
+ i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1);
+ value = 0x04;
+ /* value = 0x10; */
+ i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1);
+ /* bit 2 enable bit 1:2 select 0 1 2 3
+ value = 0x07; * curve 0 *
+ i2c_w(gspca_dev, PAS106_REG0f, &value, 1, 1);
+ */
+ }
+
+/* value = 0x01; */
+/* value = 0x22; */
+/* i2c_w(gspca_dev, PAS106_REG5, &value, 1, 1); */
+ /* magnetude and sign bit for DAC */
+ i2c_w(gspca_dev, PAS106_REG7, I2c4, sizeof I2c4, 1);
+ /* now set by fifo the whole colors setting */
+ reg_w(gspca_dev, ET_G_RED, GainRGBG, 6);
+ getcolors(gspca_dev);
+ setcolors(gspca_dev);
+}
+
+/* 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;
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+/* switch (vendor) { */
+/* case 0x102c: * Etoms */
+ switch (product) {
+ case 0x6151:
+ sd->sensor = SENSOR_PAS106; /* Etoms61x151 */
+ break;
+ case 0x6251:
+ sd->sensor = SENSOR_TAS5130CXX; /* Etoms61x251 */
+ break;
+/* } */
+/* break; */
+ }
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 1;
+ if (sd->sensor == SENSOR_PAS106) {
+ cam->cam_mode = sif_mode;
+ cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ } else {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ }
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ sd->autogain = AUTOGAIN_DEF;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PAS106)
+ Et_init1(gspca_dev);
+ else
+ Et_init2(gspca_dev);
+ reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
+ et_video(gspca_dev, 0); /* video off */
+ return 0;
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PAS106)
+ Et_init1(gspca_dev);
+ else
+ Et_init2(gspca_dev);
+
+ reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
+ et_video(gspca_dev, 1); /* video on */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ et_video(gspca_dev, 0); /* video off */
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ __u8 brightness = sd->brightness;
+
+ for (i = 0; i < 4; i++)
+ reg_w_val(gspca_dev, ET_O_RED + i, brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ int brightness = 0;
+
+ for (i = 0; i < 4; i++) {
+ reg_r(gspca_dev, ET_O_RED + i, 1);
+ brightness += gspca_dev->usb_buf[0];
+ }
+ sd->brightness = brightness >> 3;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
+ __u8 contrast = sd->contrast;
+
+ memset(RGBG, contrast, sizeof(RGBG) - 2);
+ reg_w(gspca_dev, ET_G_RED, RGBG, 6);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ int contrast = 0;
+
+ for (i = 0; i < 4; i++) {
+ reg_r(gspca_dev, ET_G_RED + i, 1);
+ contrast += gspca_dev->usb_buf[0];
+ }
+ sd->contrast = contrast >> 2;
+}
+
+static __u8 Et_getgainG(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PAS106) {
+ i2c_r(gspca_dev, PAS106_REG0e);
+ PDEBUG(D_CONF, "Etoms gain G %d", gspca_dev->usb_buf[0]);
+ return gspca_dev->usb_buf[0];
+ }
+ return 0x1f;
+}
+
+static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PAS106) {
+ __u8 i2cflags = 0x01;
+
+ i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3);
+ i2c_w(gspca_dev, PAS106_REG0e, &gain, 1, 1);
+ }
+}
+
+#define BLIMIT(bright) \
+ (__u8)((bright > 0x1f)?0x1f:((bright < 4)?3:bright))
+#define LIMIT(color) \
+ (unsigned char)((color > 0xff)?0xff:((color < 0)?0:color))
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ __u8 luma = 0;
+ __u8 luma_mean = 128;
+ __u8 luma_delta = 20;
+ __u8 spring = 4;
+ int Gbright = 0;
+ __u8 r, g, b;
+
+ Gbright = Et_getgainG(gspca_dev);
+ reg_r(gspca_dev, ET_LUMA_CENTER, 4);
+ g = (gspca_dev->usb_buf[0] + gspca_dev->usb_buf[3]) >> 1;
+ r = gspca_dev->usb_buf[1];
+ b = gspca_dev->usb_buf[2];
+ r = ((r << 8) - (r << 4) - (r << 3)) >> 10;
+ b = ((b << 7) >> 10);
+ g = ((g << 9) + (g << 7) + (g << 5)) >> 10;
+ luma = LIMIT(r + g + b);
+ PDEBUG(D_FRAM, "Etoms luma G %d", luma);
+ if (luma < luma_mean - luma_delta || luma > luma_mean + luma_delta) {
+ Gbright += (luma_mean - luma) >> spring;
+ Gbright = BLIMIT(Gbright);
+ PDEBUG(D_FRAM, "Etoms Gbright %d", Gbright);
+ Et_setgainG(gspca_dev, (__u8) Gbright);
+ }
+}
+
+#undef BLIMIT
+#undef LIMIT
+
+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;
+ int seqframe;
+
+ seqframe = data[0] & 0x3f;
+ len = (int) (((data[0] & 0xc0) << 2) | data[1]);
+ if (seqframe == 0x3f) {
+ PDEBUG(D_FRAM,
+ "header packet found datalength %d !!", len);
+ PDEBUG(D_FRAM, "G %d R %d G %d B %d",
+ data[2], data[3], data[4], data[5]);
+ data += 30;
+ /* don't change datalength as the chips provided it */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+ sd = (struct sd *) gspca_dev;
+ if (sd->ag_cnt >= 0) {
+ if (--sd->ag_cnt < 0) {
+ sd->ag_cnt = AG_CNT_START;
+ setautogain(gspca_dev);
+ }
+ }
+ return;
+ }
+ if (len) {
+ data += 8;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+ } else { /* Drop Packet */
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ }
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (val)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+#ifndef CONFIG_USB_ET61X251
+ {USB_DEVICE(0x102c, 0x6151), DVNM("Qcam Sangha CIF")},
+#endif
+ {USB_DEVICE(0x102c, 0x6251), DVNM("Qcam xxxxxx VGA")},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
new file mode 100644
index 00000000000..16e367cec76
--- /dev/null
+++ b/drivers/media/video/gspca/gspca.c
@@ -0,0 +1,1905 @@
+/*
+ * Main USB camera driver
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define MODULE_NAME "gspca"
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pagemap.h>
+#include <linux/io.h>
+#include <asm/page.h>
+#include <linux/uaccess.h>
+#include <linux/jiffies.h>
+
+#include "gspca.h"
+
+/* global values */
+#define DEF_NURBS 2 /* default number of URBs */
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("GSPCA USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+static int video_nr = -1;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int gspca_debug = D_ERR | D_PROBE;
+EXPORT_SYMBOL(gspca_debug);
+
+static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h)
+{
+ if ((pixfmt >> 24) >= '0' && (pixfmt >> 24) <= 'z') {
+ PDEBUG(D_CONF|D_STREAM, "%s %c%c%c%c %dx%d",
+ txt,
+ pixfmt & 0xff,
+ (pixfmt >> 8) & 0xff,
+ (pixfmt >> 16) & 0xff,
+ pixfmt >> 24,
+ w, h);
+ } else {
+ PDEBUG(D_CONF|D_STREAM, "%s 0x%08x %dx%d",
+ txt,
+ pixfmt,
+ w, h);
+ }
+}
+#else
+#define PDEBUG_MODE(txt, pixfmt, w, h)
+#endif
+
+/* specific memory types - !! should different from V4L2_MEMORY_xxx */
+#define GSPCA_MEMORY_NO 0 /* V4L2_MEMORY_xxx starts from 1 */
+#define GSPCA_MEMORY_READ 7
+
+#define BUF_ALL_FLAGS (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)
+
+/*
+ * VMA operations.
+ */
+static void gspca_vm_open(struct vm_area_struct *vma)
+{
+ struct gspca_frame *frame = vma->vm_private_data;
+
+ frame->vma_use_count++;
+ frame->v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED;
+}
+
+static void gspca_vm_close(struct vm_area_struct *vma)
+{
+ struct gspca_frame *frame = vma->vm_private_data;
+
+ if (--frame->vma_use_count <= 0)
+ frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_MAPPED;
+}
+
+static struct vm_operations_struct gspca_vm_ops = {
+ .open = gspca_vm_open,
+ .close = gspca_vm_close,
+};
+
+/*
+ * fill a video frame from an URB and resubmit
+ */
+static void fill_frame(struct gspca_dev *gspca_dev,
+ struct urb *urb)
+{
+ struct gspca_frame *frame;
+ __u8 *data; /* address of data in the iso message */
+ int i, j, len, st;
+ cam_pkt_op pkt_scan;
+
+ if (urb->status != 0) {
+ PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+ return; /* disconnection ? */
+ }
+ pkt_scan = gspca_dev->sd_desc->pkt_scan;
+ for (i = 0; i < urb->number_of_packets; i++) {
+
+ /* check the availability of the frame buffer */
+ j = gspca_dev->fr_i;
+ j = gspca_dev->fr_queue[j];
+ frame = &gspca_dev->frame[j];
+ if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
+ != V4L2_BUF_FLAG_QUEUED) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ break;
+ }
+
+ /* check the packet status and length */
+ len = urb->iso_frame_desc[i].actual_length;
+ if (len == 0)
+ continue;
+ st = urb->iso_frame_desc[i].status;
+ if (st) {
+ PDEBUG(D_ERR,
+ "ISOC data error: [%d] len=%d, status=%d",
+ i, len, st);
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ continue;
+ }
+
+ /* let the packet be analyzed by the subdriver */
+ PDEBUG(D_PACK, "packet [%d] o:%d l:%d",
+ i, urb->iso_frame_desc[i].offset, len);
+ data = (__u8 *) urb->transfer_buffer
+ + urb->iso_frame_desc[i].offset;
+ pkt_scan(gspca_dev, frame, data, len);
+ }
+
+ /* resubmit the URB */
+ urb->status = 0;
+ st = usb_submit_urb(urb, GFP_ATOMIC);
+ if (st < 0)
+ PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st);
+}
+
+/*
+ * ISOC message interrupt from the USB device
+ *
+ * Analyse each packet and call the subdriver for copy to the frame buffer.
+ */
+static void isoc_irq(struct urb *urb
+)
+{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+
+ PDEBUG(D_PACK, "isoc irq");
+ if (!gspca_dev->streaming)
+ return;
+ fill_frame(gspca_dev, urb);
+}
+
+/*
+ * add data to the current frame
+ *
+ * This function is called by the subdrivers at interrupt level.
+ *
+ * To build a frame, these ones must add
+ * - one FIRST_PACKET
+ * - 0 or many INTER_PACKETs
+ * - one LAST_PACKET
+ * DISCARD_PACKET invalidates the whole frame.
+ * On LAST_PACKET, a new frame is returned.
+ */
+struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
+ int packet_type,
+ struct gspca_frame *frame,
+ const __u8 *data,
+ int len)
+{
+ int i, j;
+
+ PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len);
+
+ /* when start of a new frame, if the current frame buffer
+ * is not queued, discard the whole frame */
+ if (packet_type == FIRST_PACKET) {
+ if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
+ != V4L2_BUF_FLAG_QUEUED) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return frame;
+ }
+ frame->data_end = frame->data;
+ jiffies_to_timeval(get_jiffies_64(),
+ &frame->v4l2_buf.timestamp);
+ frame->v4l2_buf.sequence = ++gspca_dev->sequence;
+ } else if (gspca_dev->last_packet_type == DISCARD_PACKET) {
+ return frame;
+ }
+
+ /* append the packet to the frame buffer */
+ if (len > 0) {
+ if (frame->data_end - frame->data + len
+ > frame->v4l2_buf.length) {
+ PDEBUG(D_ERR|D_PACK, "frame overflow %zd > %d",
+ frame->data_end - frame->data + len,
+ frame->v4l2_buf.length);
+ packet_type = DISCARD_PACKET;
+ } else {
+ memcpy(frame->data_end, data, len);
+ frame->data_end += len;
+ }
+ }
+ gspca_dev->last_packet_type = packet_type;
+
+ /* if last packet, wake the application and advance in the queue */
+ if (packet_type == LAST_PACKET) {
+ frame->v4l2_buf.bytesused = frame->data_end - frame->data;
+ frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
+ frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
+ atomic_inc(&gspca_dev->nevent);
+ wake_up_interruptible(&gspca_dev->wq); /* event = new frame */
+ i = (gspca_dev->fr_i + 1) % gspca_dev->nframes;
+ gspca_dev->fr_i = i;
+ PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d",
+ frame->v4l2_buf.bytesused,
+ gspca_dev->fr_q,
+ i,
+ gspca_dev->fr_o);
+ j = gspca_dev->fr_queue[i];
+ frame = &gspca_dev->frame[j];
+ }
+ return frame;
+}
+EXPORT_SYMBOL(gspca_frame_add);
+
+static int gspca_is_compressed(__u32 format)
+{
+ switch (format) {
+ case V4L2_PIX_FMT_MJPEG:
+ case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_SPCA561:
+ case V4L2_PIX_FMT_PAC207:
+ return 1;
+ }
+ return 0;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+ void *mem;
+ unsigned long adr;
+
+/* size = PAGE_ALIGN(size); (already done) */
+ mem = vmalloc_32(size);
+ if (mem != NULL) {
+ adr = (unsigned long) mem;
+ while ((long) size > 0) {
+ SetPageReserved(vmalloc_to_page((void *) adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ }
+ return mem;
+}
+
+static void rvfree(void *mem, long size)
+{
+ unsigned long adr;
+
+ adr = (unsigned long) mem;
+ while (size > 0) {
+ ClearPageReserved(vmalloc_to_page((void *) adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ vfree(mem);
+}
+
+static int frame_alloc(struct gspca_dev *gspca_dev,
+ unsigned int count)
+{
+ struct gspca_frame *frame;
+ unsigned int frsz;
+ int i;
+
+ i = gspca_dev->curr_mode;
+ frsz = gspca_dev->cam.cam_mode[i].sizeimage;
+ PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
+ frsz = PAGE_ALIGN(frsz);
+ gspca_dev->frsz = frsz;
+ if (count > GSPCA_MAX_FRAMES)
+ count = GSPCA_MAX_FRAMES;
+ gspca_dev->frbuf = rvmalloc(frsz * count);
+ if (!gspca_dev->frbuf) {
+ err("frame alloc failed");
+ return -ENOMEM;
+ }
+ gspca_dev->nframes = count;
+ for (i = 0; i < count; i++) {
+ frame = &gspca_dev->frame[i];
+ frame->v4l2_buf.index = i;
+ frame->v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ frame->v4l2_buf.flags = 0;
+ frame->v4l2_buf.field = V4L2_FIELD_NONE;
+ frame->v4l2_buf.length = frsz;
+ frame->v4l2_buf.memory = gspca_dev->memory;
+ frame->v4l2_buf.sequence = 0;
+ frame->data = frame->data_end =
+ gspca_dev->frbuf + i * frsz;
+ frame->v4l2_buf.m.offset = i * frsz;
+ }
+ gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ gspca_dev->sequence = 0;
+ atomic_set(&gspca_dev->nevent, 0);
+ return 0;
+}
+
+static void frame_free(struct gspca_dev *gspca_dev)
+{
+ int i;
+
+ PDEBUG(D_STREAM, "frame free");
+ if (gspca_dev->frbuf != NULL) {
+ rvfree(gspca_dev->frbuf,
+ gspca_dev->nframes * gspca_dev->frsz);
+ gspca_dev->frbuf = NULL;
+ for (i = 0; i < gspca_dev->nframes; i++)
+ gspca_dev->frame[i].data = NULL;
+ }
+ gspca_dev->nframes = 0;
+}
+
+static void destroy_urbs(struct gspca_dev *gspca_dev)
+{
+ struct urb *urb;
+ unsigned int i;
+
+ PDEBUG(D_STREAM, "kill transfer");
+ for (i = 0; i < MAX_NURBS; ++i) {
+ urb = gspca_dev->urb[i];
+ if (urb == NULL)
+ break;
+
+ gspca_dev->urb[i] = NULL;
+ usb_kill_urb(urb);
+ if (urb->transfer_buffer != NULL)
+ usb_buffer_free(gspca_dev->dev,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer,
+ urb->transfer_dma);
+ usb_free_urb(urb);
+ }
+}
+
+/*
+ * search an input isochronous endpoint in an alternate setting
+ */
+static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt,
+ __u8 epaddr)
+{
+ struct usb_host_endpoint *ep;
+ int i, attr;
+
+ epaddr |= USB_DIR_IN;
+ for (i = 0; i < alt->desc.bNumEndpoints; i++) {
+ ep = &alt->endpoint[i];
+ if (ep->desc.bEndpointAddress == epaddr) {
+ attr = ep->desc.bmAttributes
+ & USB_ENDPOINT_XFERTYPE_MASK;
+ if (attr == USB_ENDPOINT_XFER_ISOC)
+ return ep;
+ break;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * search an input isochronous endpoint
+ *
+ * The endpoint is defined by the subdriver.
+ * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep).
+ * This routine may be called many times when the bandwidth is too small
+ * (the bandwidth is checked on urb submit).
+ */
+struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev)
+{
+ struct usb_interface *intf;
+ struct usb_host_endpoint *ep;
+ int i, ret;
+
+ intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+ ep = NULL;
+ i = gspca_dev->alt; /* previous alt setting */
+ while (--i > 0) { /* alt 0 is unusable */
+ ep = alt_isoc(&intf->altsetting[i], gspca_dev->cam.epaddr);
+ if (ep)
+ break;
+ }
+ if (ep == NULL) {
+ err("no ISOC endpoint found");
+ return NULL;
+ }
+ PDEBUG(D_STREAM, "use ISOC alt %d ep 0x%02x",
+ i, ep->desc.bEndpointAddress);
+ ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
+ if (ret < 0) {
+ err("set interface err %d", ret);
+ return NULL;
+ }
+ gspca_dev->alt = i; /* memorize the current alt setting */
+ return ep;
+}
+
+/*
+ * create the isochronous URBs
+ */
+static int create_urbs(struct gspca_dev *gspca_dev,
+ struct usb_host_endpoint *ep)
+{
+ struct urb *urb;
+ int n, nurbs, i, psize, npkt, bsize;
+
+ /* calculate the packet size and the number of packets */
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+
+ /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ npkt = ISO_MAX_SIZE / psize;
+ if (npkt > ISO_MAX_PKT)
+ npkt = ISO_MAX_PKT;
+ bsize = psize * npkt;
+ PDEBUG(D_STREAM,
+ "isoc %d pkts size %d (bsize:%d)", npkt, psize, bsize);
+ nurbs = DEF_NURBS;
+ gspca_dev->nurbs = nurbs;
+ for (n = 0; n < nurbs; n++) {
+ urb = usb_alloc_urb(npkt, GFP_KERNEL);
+ if (!urb) {
+ err("usb_alloc_urb failed");
+ return -ENOMEM;
+ }
+ urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
+ bsize,
+ GFP_KERNEL,
+ &urb->transfer_dma);
+
+ if (urb->transfer_buffer == NULL) {
+ usb_free_urb(urb);
+ destroy_urbs(gspca_dev);
+ err("usb_buffer_urb failed");
+ return -ENOMEM;
+ }
+ gspca_dev->urb[n] = urb;
+ urb->dev = gspca_dev->dev;
+ urb->context = gspca_dev;
+ urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
+ ep->desc.bEndpointAddress);
+ urb->transfer_flags = URB_ISO_ASAP
+ | URB_NO_TRANSFER_DMA_MAP;
+ urb->interval = ep->desc.bInterval;
+ urb->complete = isoc_irq;
+ urb->number_of_packets = npkt;
+ urb->transfer_buffer_length = bsize;
+ for (i = 0; i < npkt; i++) {
+ urb->iso_frame_desc[i].length = psize;
+ urb->iso_frame_desc[i].offset = psize * i;
+ }
+ }
+ return 0;
+}
+
+/*
+ * start the USB transfer
+ */
+static int gspca_init_transfer(struct gspca_dev *gspca_dev)
+{
+ struct usb_host_endpoint *ep;
+ int n, ret;
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+
+ /* set the higher alternate setting and
+ * loop until urb submit succeeds */
+ gspca_dev->alt = gspca_dev->nbalt;
+ for (;;) {
+ PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
+ ep = get_isoc_ep(gspca_dev);
+ if (ep == NULL) {
+ ret = -EIO;
+ goto out;
+ }
+ ret = create_urbs(gspca_dev, ep);
+ if (ret < 0)
+ goto out;
+
+ /* start the cam */
+ gspca_dev->sd_desc->start(gspca_dev);
+ gspca_dev->streaming = 1;
+ atomic_set(&gspca_dev->nevent, 0);
+
+ /* submit the URBs */
+ for (n = 0; n < gspca_dev->nurbs; n++) {
+ ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);
+ if (ret < 0) {
+ PDEBUG(D_ERR|D_STREAM,
+ "usb_submit_urb [%d] err %d", n, ret);
+ gspca_dev->streaming = 0;
+ destroy_urbs(gspca_dev);
+ if (ret == -ENOSPC)
+ break; /* try the previous alt */
+ goto out;
+ }
+ }
+ if (ret >= 0)
+ break;
+ }
+out:
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+}
+
+static int gspca_set_alt0(struct gspca_dev *gspca_dev)
+{
+ int ret;
+
+ ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
+ if (ret < 0)
+ PDEBUG(D_ERR|D_STREAM, "set interface 0 err %d", ret);
+ return ret;
+}
+
+/* Note both the queue and the usb lock should be hold when calling this */
+static void gspca_stream_off(struct gspca_dev *gspca_dev)
+{
+ gspca_dev->streaming = 0;
+ atomic_set(&gspca_dev->nevent, 0);
+ if (gspca_dev->present) {
+ gspca_dev->sd_desc->stopN(gspca_dev);
+ destroy_urbs(gspca_dev);
+ gspca_set_alt0(gspca_dev);
+ gspca_dev->sd_desc->stop0(gspca_dev);
+ PDEBUG(D_STREAM, "stream off OK");
+ }
+}
+
+static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
+{
+ int i;
+
+ i = gspca_dev->cam.nmodes - 1; /* take the highest mode */
+ gspca_dev->curr_mode = i;
+ gspca_dev->width = gspca_dev->cam.cam_mode[i].width;
+ gspca_dev->height = gspca_dev->cam.cam_mode[i].height;
+ gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat;
+}
+
+static int wxh_to_mode(struct gspca_dev *gspca_dev,
+ int width, int height)
+{
+ int i;
+
+ for (i = gspca_dev->cam.nmodes; --i > 0; ) {
+ if (width >= gspca_dev->cam.cam_mode[i].width
+ && height >= gspca_dev->cam.cam_mode[i].height)
+ break;
+ }
+ return i;
+}
+
+/*
+ * search a mode with the right pixel format
+ */
+static int gspca_get_mode(struct gspca_dev *gspca_dev,
+ int mode,
+ int pixfmt)
+{
+ int modeU, modeD;
+
+ modeU = modeD = mode;
+ while ((modeU < gspca_dev->cam.nmodes) || modeD >= 0) {
+ if (--modeD >= 0) {
+ if (gspca_dev->cam.cam_mode[modeD].pixelformat
+ == pixfmt)
+ return modeD;
+ }
+ if (++modeU < gspca_dev->cam.nmodes) {
+ if (gspca_dev->cam.cam_mode[modeU].pixelformat
+ == pixfmt)
+ return modeU;
+ }
+ }
+ return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmtdesc)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int i, j, index;
+ __u32 fmt_tb[8];
+
+ /* give an index to each format */
+ index = 0;
+ j = 0;
+ for (i = gspca_dev->cam.nmodes; --i >= 0; ) {
+ fmt_tb[index] = gspca_dev->cam.cam_mode[i].pixelformat;
+ j = 0;
+ for (;;) {
+ if (fmt_tb[j] == fmt_tb[index])
+ break;
+ j++;
+ }
+ if (j == index) {
+ if (fmtdesc->index == index)
+ break; /* new format */
+ index++;
+ if (index >= sizeof fmt_tb / sizeof fmt_tb[0])
+ return -EINVAL;
+ }
+ }
+ if (i < 0)
+ return -EINVAL; /* no more format */
+
+ fmtdesc->pixelformat = fmt_tb[index];
+ if (gspca_is_compressed(fmt_tb[index]))
+ fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
+ fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmtdesc->description[0] = fmtdesc->pixelformat & 0xff;
+ fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff;
+ fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff;
+ fmtdesc->description[3] = fmtdesc->pixelformat >> 24;
+ fmtdesc->description[4] = '\0';
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int mode;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ mode = gspca_dev->curr_mode;
+ memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode],
+ sizeof fmt->fmt.pix);
+ return 0;
+}
+
+static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
+ struct v4l2_format *fmt)
+{
+ int w, h, mode, mode2;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ w = fmt->fmt.pix.width;
+ h = fmt->fmt.pix.height;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (gspca_debug & D_CONF)
+ PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h);
+#endif
+ /* search the closest mode for width and height */
+ mode = wxh_to_mode(gspca_dev, w, h);
+
+ /* OK if right palette */
+ if (gspca_dev->cam.cam_mode[mode].pixelformat
+ != fmt->fmt.pix.pixelformat) {
+
+ /* else, search the closest mode with the same pixel format */
+ mode2 = gspca_get_mode(gspca_dev, mode,
+ fmt->fmt.pix.pixelformat);
+ if (mode2 >= 0)
+ mode = mode2;
+/* else
+ ; * no chance, return this mode */
+ }
+ memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode],
+ sizeof fmt->fmt.pix);
+ return mode; /* used when s_fmt */
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file,
+ void *priv,
+ struct v4l2_format *fmt)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int ret;
+
+ ret = try_fmt_vid_cap(gspca_dev, fmt);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+
+ ret = try_fmt_vid_cap(gspca_dev, fmt);
+ if (ret < 0)
+ goto out;
+
+ if (gspca_dev->nframes != 0
+ && fmt->fmt.pix.sizeimage > gspca_dev->frsz) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ret == gspca_dev->curr_mode) {
+ ret = 0;
+ goto out; /* same mode */
+ }
+
+ if (gspca_dev->streaming) {
+ ret = -EBUSY;
+ goto out;
+ }
+ gspca_dev->width = fmt->fmt.pix.width;
+ gspca_dev->height = fmt->fmt.pix.height;
+ gspca_dev->pixfmt = fmt->fmt.pix.pixelformat;
+ gspca_dev->curr_mode = ret;
+
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
+static int dev_open(struct inode *inode, struct file *file)
+{
+ struct gspca_dev *gspca_dev;
+ int ret;
+
+ PDEBUG(D_STREAM, "%s open", current->comm);
+ gspca_dev = (struct gspca_dev *) video_devdata(file);
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+ if (!gspca_dev->present) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* if not done yet, initialize the sensor */
+ if (gspca_dev->users == 0) {
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
+ ret = -ERESTARTSYS;
+ goto out;
+ }
+ ret = gspca_dev->sd_desc->open(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ if (ret != 0) {
+ PDEBUG(D_ERR|D_CONF, "init device failed %d", ret);
+ goto out;
+ }
+ } else if (gspca_dev->users > 4) { /* (arbitrary value) */
+ ret = -EBUSY;
+ goto out;
+ }
+ gspca_dev->users++;
+ file->private_data = gspca_dev;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ /* activate the v4l2 debug */
+ if (gspca_debug & D_V4L2)
+ gspca_dev->vdev.debug |= 3;
+ else
+ gspca_dev->vdev.debug &= ~3;
+#endif
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ if (ret != 0)
+ PDEBUG(D_ERR|D_STREAM, "open failed err %d", ret);
+ else
+ PDEBUG(D_STREAM, "open done");
+ return ret;
+}
+
+static int dev_close(struct inode *inode, struct file *file)
+{
+ struct gspca_dev *gspca_dev = file->private_data;
+
+ PDEBUG(D_STREAM, "%s close", current->comm);
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+ gspca_dev->users--;
+
+ /* if the file did the capture, free the streaming resources */
+ if (gspca_dev->capt_file == file) {
+ mutex_lock(&gspca_dev->usb_lock);
+ if (gspca_dev->streaming)
+ gspca_stream_off(gspca_dev);
+ gspca_dev->sd_desc->close(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ frame_free(gspca_dev);
+ gspca_dev->capt_file = NULL;
+ gspca_dev->memory = GSPCA_MEMORY_NO;
+ }
+ file->private_data = NULL;
+ mutex_unlock(&gspca_dev->queue_lock);
+ PDEBUG(D_STREAM, "close done");
+ return 0;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct gspca_dev *gspca_dev = priv;
+
+ memset(cap, 0, sizeof *cap);
+ strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver);
+ strncpy(cap->card, gspca_dev->cam.dev_name, sizeof cap->card);
+ strncpy(cap->bus_info, gspca_dev->dev->bus->bus_name,
+ sizeof cap->bus_info);
+ cap->version = DRIVER_VERSION_NUMBER;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_STREAMING
+ | V4L2_CAP_READWRITE;
+ return 0;
+}
+
+/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *q_ctrl)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int i;
+ u32 id;
+
+ id = q_ctrl->id;
+ if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+ id &= V4L2_CTRL_ID_MASK;
+ id++;
+ for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
+ if (id >= gspca_dev->sd_desc->ctrls[i].qctrl.id) {
+ memcpy(q_ctrl,
+ &gspca_dev->sd_desc->ctrls[i].qctrl,
+ sizeof *q_ctrl);
+ return 0;
+ }
+ }
+ return -EINVAL;
+ }
+ for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
+ if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {
+ memcpy(q_ctrl,
+ &gspca_dev->sd_desc->ctrls[i].qctrl,
+ sizeof *q_ctrl);
+ return 0;
+ }
+ }
+ if (id >= V4L2_CID_BASE
+ && id <= V4L2_CID_LASTP1) {
+ q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct gspca_dev *gspca_dev = priv;
+ const struct ctrl *ctrls;
+ int i, ret;
+
+ for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
+ i < gspca_dev->sd_desc->nctrls;
+ i++, ctrls++) {
+ if (ctrl->id != ctrls->qctrl.id)
+ continue;
+ if (ctrl->value < ctrls->qctrl.minimum
+ && ctrl->value > ctrls->qctrl.maximum)
+ return -ERANGE;
+ PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ ret = ctrls->set(gspca_dev, ctrl->value);
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct gspca_dev *gspca_dev = priv;
+
+ const struct ctrl *ctrls;
+ int i, ret;
+
+ for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
+ i < gspca_dev->sd_desc->nctrls;
+ i++, ctrls++) {
+ if (ctrl->id != ctrls->qctrl.id)
+ continue;
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ ret = ctrls->get(gspca_dev, &ctrl->value);
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+ }
+ return -EINVAL;
+}
+
+static int vidioc_querymenu(struct file *file, void *priv,
+ struct v4l2_querymenu *qmenu)
+{
+ struct gspca_dev *gspca_dev = priv;
+
+ if (!gspca_dev->sd_desc->querymenu)
+ return -EINVAL;
+ return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu);
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct gspca_dev *gspca_dev = priv;
+
+ if (input->index != 0)
+ return -EINVAL;
+ memset(input, 0, sizeof *input);
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ strncpy(input->name, gspca_dev->sd_desc->name,
+ sizeof input->name);
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+ return (0);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int i, ret = 0;
+
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ switch (rb->memory) {
+ case GSPCA_MEMORY_READ: /* (internal call) */
+ case V4L2_MEMORY_MMAP:
+ case V4L2_MEMORY_USERPTR:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+
+ if (gspca_dev->memory != GSPCA_MEMORY_NO
+ && gspca_dev->memory != rb->memory) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* only one file may do the capture */
+ if (gspca_dev->capt_file != NULL
+ && gspca_dev->capt_file != file) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* if allocated, the buffers must not be mapped */
+ for (i = 0; i < gspca_dev->nframes; i++) {
+ if (gspca_dev->frame[i].vma_use_count) {
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+
+ /* stop streaming */
+ if (gspca_dev->streaming) {
+ mutex_lock(&gspca_dev->usb_lock);
+ gspca_stream_off(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ }
+
+ /* free the previous allocated buffers, if any */
+ if (gspca_dev->nframes != 0) {
+ frame_free(gspca_dev);
+ gspca_dev->capt_file = NULL;
+ }
+ if (rb->count == 0) /* unrequest */
+ goto out;
+ gspca_dev->memory = rb->memory;
+ ret = frame_alloc(gspca_dev, rb->count);
+ if (ret == 0) {
+ rb->count = gspca_dev->nframes;
+ gspca_dev->capt_file = file;
+ }
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ PDEBUG(D_STREAM, "reqbufs st:%d c:%d", ret, rb->count);
+ return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *v4l2_buf)
+{
+ struct gspca_dev *gspca_dev = priv;
+ struct gspca_frame *frame;
+
+ if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+ || v4l2_buf->index < 0
+ || v4l2_buf->index >= gspca_dev->nframes)
+ return -EINVAL;
+
+ frame = &gspca_dev->frame[v4l2_buf->index];
+ memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
+ return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int ret;
+
+ if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+ if (!gspca_dev->present) {
+ ret = -ENODEV;
+ goto out;
+ }
+ if (gspca_dev->nframes == 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (!gspca_dev->streaming) {
+ ret = gspca_init_transfer(gspca_dev);
+ if (ret < 0)
+ goto out;
+ }
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (gspca_debug & D_STREAM) {
+ PDEBUG_MODE("stream on OK",
+ gspca_dev->pixfmt,
+ gspca_dev->width,
+ gspca_dev->height);
+ }
+#endif
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int i, ret;
+
+ if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (!gspca_dev->streaming)
+ return 0;
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+
+ /* stop streaming */
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
+ ret = -ERESTARTSYS;
+ goto out;
+ }
+ gspca_stream_off(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+
+ /* empty the application queues */
+ for (i = 0; i < gspca_dev->nframes; i++)
+ gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS;
+ gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ gspca_dev->sequence = 0;
+ atomic_set(&gspca_dev->nevent, 0);
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
+static int vidioc_g_jpegcomp(struct file *file, void *priv,
+ struct v4l2_jpegcompression *jpegcomp)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int ret;
+
+ if (!gspca_dev->sd_desc->get_jcomp)
+ return -EINVAL;
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+}
+
+static int vidioc_s_jpegcomp(struct file *file, void *priv,
+ struct v4l2_jpegcompression *jpegcomp)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ if (!gspca_dev->sd_desc->set_jcomp)
+ return -EINVAL;
+ ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+}
+
+static int vidioc_g_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct gspca_dev *gspca_dev = priv;
+
+ memset(parm, 0, sizeof *parm);
+ parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ parm->parm.capture.readbuffers = gspca_dev->nbufread;
+ return 0;
+}
+
+static int vidioc_s_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int n;
+
+ n = parm->parm.capture.readbuffers;
+ if (n == 0 || n > GSPCA_MAX_FRAMES)
+ parm->parm.capture.readbuffers = gspca_dev->nbufread;
+ else
+ gspca_dev->nbufread = n;
+ return 0;
+}
+
+static int vidioc_s_std(struct file *filp, void *priv,
+ v4l2_std_id *parm)
+{
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv,
+ struct video_mbuf *mbuf)
+{
+ struct gspca_dev *gspca_dev = file->private_data;
+ int i;
+
+ PDEBUG(D_STREAM, "cgmbuf");
+ if (gspca_dev->nframes == 0) {
+ int ret;
+
+ {
+ struct v4l2_format fmt;
+
+ memset(&fmt, 0, sizeof fmt);
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ i = gspca_dev->cam.nmodes - 1; /* highest mode */
+ fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
+ fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height;
+ fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
+ ret = vidioc_s_fmt_vid_cap(file, priv, &fmt);
+ if (ret != 0)
+ return ret;
+ }
+ {
+ struct v4l2_requestbuffers rb;
+
+ memset(&rb, 0, sizeof rb);
+ rb.count = 4;
+ rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rb.memory = V4L2_MEMORY_MMAP;
+ ret = vidioc_reqbufs(file, priv, &rb);
+ if (ret != 0)
+ return ret;
+ }
+ }
+ mbuf->frames = gspca_dev->nframes;
+ mbuf->size = gspca_dev->frsz * gspca_dev->nframes;
+ for (i = 0; i < mbuf->frames; i++)
+ mbuf->offsets[i] = gspca_dev->frame[i].v4l2_buf.m.offset;
+ return 0;
+}
+#endif
+
+static int dev_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct gspca_dev *gspca_dev = file->private_data;
+ struct gspca_frame *frame;
+ struct page *page;
+ unsigned long addr, start, size;
+ int i, ret;
+
+ start = vma->vm_start;
+ size = vma->vm_end - vma->vm_start;
+ PDEBUG(D_STREAM, "mmap start:%08x size:%d", (int) start, (int) size);
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+ if (!gspca_dev->present) {
+ ret = -ENODEV;
+ goto out;
+ }
+ if (gspca_dev->capt_file != file) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ frame = NULL;
+ for (i = 0; i < gspca_dev->nframes; ++i) {
+ if (gspca_dev->frame[i].v4l2_buf.memory != V4L2_MEMORY_MMAP) {
+ PDEBUG(D_STREAM, "mmap bad memory type");
+ break;
+ }
+ if ((gspca_dev->frame[i].v4l2_buf.m.offset >> PAGE_SHIFT)
+ == vma->vm_pgoff) {
+ frame = &gspca_dev->frame[i];
+ break;
+ }
+ }
+ if (frame == NULL) {
+ PDEBUG(D_STREAM, "mmap no frame buffer found");
+ ret = -EINVAL;
+ goto out;
+ }
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ /* v4l1 maps all the buffers */
+ if (i != 0
+ || size != frame->v4l2_buf.length * gspca_dev->nframes)
+#endif
+ if (size != frame->v4l2_buf.length) {
+ PDEBUG(D_STREAM, "mmap bad size");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * - VM_IO marks the area as being a mmaped region for I/O to a
+ * device. It also prevents the region from being core dumped.
+ */
+ vma->vm_flags |= VM_IO;
+
+ addr = (unsigned long) frame->data;
+ while (size > 0) {
+ page = vmalloc_to_page((void *) addr);
+ ret = vm_insert_page(vma, start, page);
+ if (ret < 0)
+ goto out;
+ start += PAGE_SIZE;
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vma->vm_ops = &gspca_vm_ops;
+ vma->vm_private_data = frame;
+ gspca_vm_open(vma);
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
+/*
+ * wait for a video frame
+ *
+ * If a frame is ready, its index is returned.
+ */
+static int frame_wait(struct gspca_dev *gspca_dev,
+ int nonblock_ing)
+{
+ struct gspca_frame *frame;
+ int i, j, ret;
+
+ /* check if a frame is ready */
+ i = gspca_dev->fr_o;
+ j = gspca_dev->fr_queue[i];
+ frame = &gspca_dev->frame[j];
+ if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) {
+ atomic_dec(&gspca_dev->nevent);
+ goto ok;
+ }
+ if (nonblock_ing) /* no frame yet */
+ return -EAGAIN;
+
+ /* wait till a frame is ready */
+ for (;;) {
+ ret = wait_event_interruptible_timeout(gspca_dev->wq,
+ atomic_read(&gspca_dev->nevent) > 0,
+ msecs_to_jiffies(3000));
+ if (ret <= 0) {
+ if (ret < 0)
+ return ret; /* interrupt */
+ return -EIO; /* timeout */
+ }
+ atomic_dec(&gspca_dev->nevent);
+ if (!gspca_dev->streaming || !gspca_dev->present)
+ return -EIO;
+ i = gspca_dev->fr_o;
+ j = gspca_dev->fr_queue[i];
+ frame = &gspca_dev->frame[j];
+ if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
+ break;
+ }
+ok:
+ gspca_dev->fr_o = (i + 1) % gspca_dev->nframes;
+ PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d",
+ gspca_dev->fr_q,
+ gspca_dev->fr_i,
+ gspca_dev->fr_o);
+
+ if (gspca_dev->sd_desc->dq_callback) {
+ mutex_lock(&gspca_dev->usb_lock);
+ gspca_dev->sd_desc->dq_callback(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ }
+ return j;
+}
+
+/*
+ * dequeue a video buffer
+ *
+ * If nonblock_ing is false, block until a buffer is available.
+ */
+static int vidioc_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *v4l2_buf)
+{
+ struct gspca_dev *gspca_dev = priv;
+ struct gspca_frame *frame;
+ int i, ret;
+
+ PDEBUG(D_FRAM, "dqbuf");
+ if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (v4l2_buf->memory != gspca_dev->memory)
+ return -EINVAL;
+
+ /* if not streaming, be sure the application will not loop forever */
+ if (!(file->f_flags & O_NONBLOCK)
+ && !gspca_dev->streaming && gspca_dev->users == 1)
+ return -EINVAL;
+
+ /* only the capturing file may dequeue */
+ if (gspca_dev->capt_file != file)
+ return -EINVAL;
+
+ /* only one dequeue / read at a time */
+ if (mutex_lock_interruptible(&gspca_dev->read_lock))
+ return -ERESTARTSYS;
+
+ ret = frame_wait(gspca_dev, file->f_flags & O_NONBLOCK);
+ if (ret < 0)
+ goto out;
+ i = ret; /* frame index */
+ frame = &gspca_dev->frame[i];
+ if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {
+ if (copy_to_user((__u8 *) frame->v4l2_buf.m.userptr,
+ frame->data,
+ frame->v4l2_buf.bytesused)) {
+ PDEBUG(D_ERR|D_STREAM,
+ "dqbuf cp to user failed");
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+ frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
+ memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
+ PDEBUG(D_FRAM, "dqbuf %d", i);
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->read_lock);
+ return ret;
+}
+
+/*
+ * queue a video buffer
+ *
+ * Attempting to queue a buffer that has already been
+ * queued will return -EINVAL.
+ */
+static int vidioc_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *v4l2_buf)
+{
+ struct gspca_dev *gspca_dev = priv;
+ struct gspca_frame *frame;
+ int i, index, ret;
+
+ PDEBUG(D_FRAM, "qbuf %d", v4l2_buf->index);
+ if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+
+ index = v4l2_buf->index;
+ if ((unsigned) index >= gspca_dev->nframes) {
+ PDEBUG(D_FRAM,
+ "qbuf idx %d >= %d", index, gspca_dev->nframes);
+ ret = -EINVAL;
+ goto out;
+ }
+ if (v4l2_buf->memory != gspca_dev->memory) {
+ PDEBUG(D_FRAM, "qbuf bad memory type");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ frame = &gspca_dev->frame[index];
+ if (frame->v4l2_buf.flags & BUF_ALL_FLAGS) {
+ PDEBUG(D_FRAM, "qbuf bad state");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ frame->v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED;
+/* frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; */
+
+ if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) {
+ frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr;
+ frame->v4l2_buf.length = v4l2_buf->length;
+ }
+
+ /* put the buffer in the 'queued' queue */
+ i = gspca_dev->fr_q;
+ gspca_dev->fr_queue[i] = index;
+ gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;
+ PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",
+ gspca_dev->fr_q,
+ gspca_dev->fr_i,
+ gspca_dev->fr_o);
+
+ v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
+ v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE;
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
+/*
+ * allocate the resources for read()
+ */
+static int read_alloc(struct gspca_dev *gspca_dev,
+ struct file *file)
+{
+ struct v4l2_buffer v4l2_buf;
+ int i, ret;
+
+ PDEBUG(D_STREAM, "read alloc");
+ if (gspca_dev->nframes == 0) {
+ struct v4l2_requestbuffers rb;
+
+ memset(&rb, 0, sizeof rb);
+ rb.count = gspca_dev->nbufread;
+ rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rb.memory = GSPCA_MEMORY_READ;
+ ret = vidioc_reqbufs(file, gspca_dev, &rb);
+ if (ret != 0) {
+ PDEBUG(D_STREAM, "read reqbuf err %d", ret);
+ return ret;
+ }
+ memset(&v4l2_buf, 0, sizeof v4l2_buf);
+ v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_buf.memory = GSPCA_MEMORY_READ;
+ for (i = 0; i < gspca_dev->nbufread; i++) {
+ v4l2_buf.index = i;
+ ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
+ if (ret != 0) {
+ PDEBUG(D_STREAM, "read qbuf err: %d", ret);
+ return ret;
+ }
+ }
+ gspca_dev->memory = GSPCA_MEMORY_READ;
+ }
+
+ /* start streaming */
+ ret = vidioc_streamon(file, gspca_dev, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (ret != 0)
+ PDEBUG(D_STREAM, "read streamon err %d", ret);
+ return ret;
+}
+
+static unsigned int dev_poll(struct file *file, poll_table *wait)
+{
+ struct gspca_dev *gspca_dev = file->private_data;
+ int i, ret;
+
+ PDEBUG(D_FRAM, "poll");
+
+ poll_wait(file, &gspca_dev->wq, wait);
+ if (!gspca_dev->present)
+ return POLLERR;
+
+ /* if reqbufs is not done, the user would use read() */
+ if (gspca_dev->nframes == 0) {
+ if (gspca_dev->memory != GSPCA_MEMORY_NO)
+ return POLLERR; /* not the 1st time */
+ ret = read_alloc(gspca_dev, file);
+ if (ret != 0)
+ return POLLERR;
+ }
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
+ return POLLERR;
+ if (!gspca_dev->present) {
+ ret = POLLERR;
+ goto out;
+ }
+
+ /* check the next incoming buffer */
+ i = gspca_dev->fr_o;
+ i = gspca_dev->fr_queue[i];
+ if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
+ ret = POLLIN | POLLRDNORM; /* something to read */
+ else
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
+static ssize_t dev_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct gspca_dev *gspca_dev = file->private_data;
+ struct gspca_frame *frame;
+ struct v4l2_buffer v4l2_buf;
+ struct timeval timestamp;
+ int n, ret, ret2;
+
+ PDEBUG(D_FRAM, "read (%zd)", count);
+ if (!gspca_dev->present)
+ return -ENODEV;
+ switch (gspca_dev->memory) {
+ case GSPCA_MEMORY_NO: /* first time */
+ ret = read_alloc(gspca_dev, file);
+ if (ret != 0)
+ return ret;
+ break;
+ case GSPCA_MEMORY_READ:
+ if (gspca_dev->capt_file == file)
+ break;
+ /* fall thru */
+ default:
+ return -EINVAL;
+ }
+
+ /* get a frame */
+ jiffies_to_timeval(get_jiffies_64(), &timestamp);
+ timestamp.tv_sec--;
+ n = 2;
+ for (;;) {
+ memset(&v4l2_buf, 0, sizeof v4l2_buf);
+ v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_buf.memory = GSPCA_MEMORY_READ;
+ ret = vidioc_dqbuf(file, gspca_dev, &v4l2_buf);
+ if (ret != 0) {
+ PDEBUG(D_STREAM, "read dqbuf err %d", ret);
+ return ret;
+ }
+
+ /* if the process slept for more than 1 second,
+ * get anewer frame */
+ frame = &gspca_dev->frame[v4l2_buf.index];
+ if (--n < 0)
+ break; /* avoid infinite loop */
+ if (frame->v4l2_buf.timestamp.tv_sec >= timestamp.tv_sec)
+ break;
+ ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
+ if (ret != 0) {
+ PDEBUG(D_STREAM, "read qbuf err %d", ret);
+ return ret;
+ }
+ }
+
+ /* copy the frame */
+ if (count > frame->v4l2_buf.bytesused)
+ count = frame->v4l2_buf.bytesused;
+ ret = copy_to_user(data, frame->data, count);
+ if (ret != 0) {
+ PDEBUG(D_ERR|D_STREAM,
+ "read cp to user lack %d / %zd", ret, count);
+ ret = -EFAULT;
+ goto out;
+ }
+ ret = count;
+out:
+ /* in each case, requeue the buffer */
+ ret2 = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
+ if (ret2 != 0)
+ return ret2;
+ return ret;
+}
+
+static void dev_release(struct video_device *vfd)
+{
+ /* nothing */
+}
+
+static struct file_operations dev_fops = {
+ .owner = THIS_MODULE,
+ .open = dev_open,
+ .release = dev_close,
+ .read = dev_read,
+ .mmap = dev_mmap,
+ .ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = v4l_compat_ioctl32,
+#endif
+ .llseek = no_llseek,
+ .poll = dev_poll,
+};
+
+static struct video_device gspca_template = {
+ .name = "gspca main driver",
+ .type = VID_TYPE_CAPTURE,
+ .fops = &dev_fops,
+ .release = dev_release, /* mandatory */
+ .minor = -1,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_querymenu = vidioc_querymenu,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_jpegcomp = vidioc_g_jpegcomp,
+ .vidioc_s_jpegcomp = vidioc_s_jpegcomp,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_s_parm = vidioc_s_parm,
+ .vidioc_s_std = vidioc_s_std,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
+};
+
+/*
+ * probe and create a new gspca device
+ *
+ * This function must be called by the sub-driver when it is
+ * called for probing a new device.
+ */
+int gspca_dev_probe(struct usb_interface *intf,
+ const struct usb_device_id *id,
+ const struct sd_desc *sd_desc,
+ int dev_size,
+ struct module *module)
+{
+ struct usb_interface_descriptor *interface;
+ struct gspca_dev *gspca_dev;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ int ret;
+
+ PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);
+
+ /* we don't handle multi-config cameras */
+ if (dev->descriptor.bNumConfigurations != 1)
+ return -ENODEV;
+ interface = &intf->cur_altsetting->desc;
+ if (interface->bInterfaceNumber > 0)
+ return -ENODEV;
+
+ /* create the device */
+ if (dev_size < sizeof *gspca_dev)
+ dev_size = sizeof *gspca_dev;
+ gspca_dev = kzalloc(dev_size, GFP_KERNEL);
+ if (gspca_dev == NULL) {
+ err("couldn't kzalloc gspca struct");
+ return -EIO;
+ }
+ gspca_dev->dev = dev;
+ gspca_dev->iface = interface->bInterfaceNumber;
+ gspca_dev->nbalt = intf->num_altsetting;
+ gspca_dev->sd_desc = sd_desc;
+/* gspca_dev->users = 0; (done by kzalloc) */
+ gspca_dev->nbufread = 2;
+
+ /* configure the subdriver */
+ ret = gspca_dev->sd_desc->config(gspca_dev, id);
+ if (ret < 0)
+ goto out;
+ ret = gspca_set_alt0(gspca_dev);
+ if (ret < 0)
+ goto out;
+ gspca_set_default_mode(gspca_dev);
+
+ mutex_init(&gspca_dev->usb_lock);
+ mutex_init(&gspca_dev->read_lock);
+ mutex_init(&gspca_dev->queue_lock);
+ init_waitqueue_head(&gspca_dev->wq);
+
+ /* init video stuff */
+ memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template);
+ gspca_dev->vdev.dev = &dev->dev;
+ memcpy(&gspca_dev->fops, &dev_fops, sizeof gspca_dev->fops);
+ gspca_dev->vdev.fops = &gspca_dev->fops;
+ gspca_dev->fops.owner = module; /* module protection */
+ ret = video_register_device(&gspca_dev->vdev,
+ VFL_TYPE_GRABBER,
+ video_nr);
+ if (ret < 0) {
+ err("video_register_device err %d", ret);
+ goto out;
+ }
+
+ gspca_dev->present = 1;
+ usb_set_intfdata(intf, gspca_dev);
+ PDEBUG(D_PROBE, "probe ok");
+ return 0;
+out:
+ kfree(gspca_dev);
+ return ret;
+}
+EXPORT_SYMBOL(gspca_dev_probe);
+
+/*
+ * USB disconnection
+ *
+ * This function must be called by the sub-driver
+ * when the device disconnects, after the specific resources are freed.
+ */
+void gspca_disconnect(struct usb_interface *intf)
+{
+ struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+ if (!gspca_dev)
+ return;
+ gspca_dev->present = 0;
+ mutex_lock(&gspca_dev->queue_lock);
+ mutex_lock(&gspca_dev->usb_lock);
+ gspca_dev->streaming = 0;
+ destroy_urbs(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ mutex_unlock(&gspca_dev->queue_lock);
+ while (gspca_dev->users != 0) { /* wait until fully closed */
+ atomic_inc(&gspca_dev->nevent);
+ wake_up_interruptible(&gspca_dev->wq); /* wake processes */
+ schedule();
+ }
+/* We don't want people trying to open up the device */
+ video_unregister_device(&gspca_dev->vdev);
+/* Free the memory */
+ kfree(gspca_dev);
+ PDEBUG(D_PROBE, "disconnect complete");
+}
+EXPORT_SYMBOL(gspca_disconnect);
+
+/* -- cam driver utility functions -- */
+
+/* auto gain and exposure algorithm based on the knee algorithm described here:
+ http://ytse.tricolour.net/docs/LowLightOptimization.html
+
+ Returns 0 if no changes were made, 1 if the gain and or exposure settings
+ where changed. */
+int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
+ int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee)
+{
+ int i, steps, gain, orig_gain, exposure, orig_exposure, autogain;
+ const struct ctrl *gain_ctrl = NULL;
+ const struct ctrl *exposure_ctrl = NULL;
+ const struct ctrl *autogain_ctrl = NULL;
+ int retval = 0;
+
+ for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
+ if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN)
+ gain_ctrl = &gspca_dev->sd_desc->ctrls[i];
+ if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE)
+ exposure_ctrl = &gspca_dev->sd_desc->ctrls[i];
+ if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_AUTOGAIN)
+ autogain_ctrl = &gspca_dev->sd_desc->ctrls[i];
+ }
+ if (!gain_ctrl || !exposure_ctrl || !autogain_ctrl) {
+ PDEBUG(D_ERR, "Error: gspca_auto_gain_n_exposure called "
+ "on cam without (auto)gain/exposure");
+ return 0;
+ }
+
+ if (gain_ctrl->get(gspca_dev, &gain) ||
+ exposure_ctrl->get(gspca_dev, &exposure) ||
+ autogain_ctrl->get(gspca_dev, &autogain) || !autogain)
+ return 0;
+
+ orig_gain = gain;
+ orig_exposure = exposure;
+
+ /* If we are of a multiple of deadzone, do multiple steps to reach the
+ desired lumination fast (with the risc of a slight overshoot) */
+ steps = abs(desired_avg_lum - avg_lum) / deadzone;
+
+ PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d\n",
+ avg_lum, desired_avg_lum, steps);
+
+ for (i = 0; i < steps; i++) {
+ if (avg_lum > desired_avg_lum) {
+ if (gain > gain_knee)
+ gain--;
+ else if (exposure > exposure_knee)
+ exposure--;
+ else if (gain > gain_ctrl->qctrl.default_value)
+ gain--;
+ else if (exposure > exposure_ctrl->qctrl.minimum)
+ exposure--;
+ else if (gain > gain_ctrl->qctrl.minimum)
+ gain--;
+ else
+ break;
+ } else {
+ if (gain < gain_ctrl->qctrl.default_value)
+ gain++;
+ else if (exposure < exposure_knee)
+ exposure++;
+ else if (gain < gain_knee)
+ gain++;
+ else if (exposure < exposure_ctrl->qctrl.maximum)
+ exposure++;
+ else if (gain < gain_ctrl->qctrl.maximum)
+ gain++;
+ else
+ break;
+ }
+ }
+
+ if (gain != orig_gain) {
+ gain_ctrl->set(gspca_dev, gain);
+ retval = 1;
+ }
+ if (exposure != orig_exposure) {
+ exposure_ctrl->set(gspca_dev, exposure);
+ retval = 1;
+ }
+
+ return retval;
+}
+EXPORT_SYMBOL(gspca_auto_gain_n_exposure);
+
+/* -- module insert / remove -- */
+static int __init gspca_init(void)
+{
+ info("main v%s registered", version);
+ return 0;
+}
+static void __exit gspca_exit(void)
+{
+ info("main deregistered");
+}
+
+module_init(gspca_init);
+module_exit(gspca_exit);
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+module_param_named(debug, gspca_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+ "Debug (bit) 0x01:error 0x02:probe 0x04:config"
+ " 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout"
+ " 0x0100: v4l2");
+#endif
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
new file mode 100644
index 00000000000..3fd2c4eee20
--- /dev/null
+++ b/drivers/media/video/gspca/gspca.h
@@ -0,0 +1,176 @@
+#ifndef GSPCAV2_H
+#define GSPCAV2_H
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/mutex.h>
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/* GSPCA our debug messages */
+extern int gspca_debug;
+#define PDEBUG(level, fmt, args...) \
+ do {\
+ if (gspca_debug & (level)) \
+ printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \
+ } while (0)
+#define D_ERR 0x01
+#define D_PROBE 0x02
+#define D_CONF 0x04
+#define D_STREAM 0x08
+#define D_FRAM 0x10
+#define D_PACK 0x20
+#define D_USBI 0x40
+#define D_USBO 0x80
+#define D_V4L2 0x0100
+#else
+#define PDEBUG(level, fmt, args...)
+#endif
+#undef err
+#define err(fmt, args...) \
+ do {\
+ printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args); \
+ } while (0)
+#undef info
+#define info(fmt, args...) \
+ do {\
+ printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \
+ } while (0)
+#undef warn
+#define warn(fmt, args...) \
+ do {\
+ printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args); \
+ } while (0)
+
+#define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */
+/* ISOC transfers */
+#define MAX_NURBS 16 /* max number of URBs */
+#define ISO_MAX_PKT 32 /* max number of packets in an ISOC transfer */
+#define ISO_MAX_SIZE 0x8000 /* max size of one URB buffer (32 Kb) */
+
+/* device information - set at probe time */
+struct cam {
+ char *dev_name;
+ struct v4l2_pix_format *cam_mode; /* size nmodes */
+ char nmodes;
+ __u8 epaddr;
+};
+
+struct gspca_dev;
+struct gspca_frame;
+
+/* subdriver operations */
+typedef int (*cam_op) (struct gspca_dev *);
+typedef void (*cam_v_op) (struct gspca_dev *);
+typedef int (*cam_cf_op) (struct gspca_dev *, const struct usb_device_id *);
+typedef int (*cam_jpg_op) (struct gspca_dev *,
+ struct v4l2_jpegcompression *);
+typedef int (*cam_qmnu_op) (struct gspca_dev *,
+ struct v4l2_querymenu *);
+typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame,
+ __u8 *data,
+ int len);
+
+struct ctrl {
+ struct v4l2_queryctrl qctrl;
+ int (*set)(struct gspca_dev *, __s32);
+ int (*get)(struct gspca_dev *, __s32 *);
+};
+
+/* subdriver description */
+struct sd_desc {
+/* information */
+ const char *name; /* sub-driver name */
+/* controls */
+ const struct ctrl *ctrls;
+ int nctrls;
+/* operations */
+ cam_cf_op config; /* called on probe */
+ cam_op open; /* called on open */
+ cam_v_op start; /* called on stream on */
+ cam_v_op stopN; /* called on stream off - main alt */
+ cam_v_op stop0; /* called on stream off - alt 0 */
+ cam_v_op close; /* called on close */
+ cam_pkt_op pkt_scan;
+/* optional operations */
+ cam_v_op dq_callback; /* called when a frame has been dequeued */
+ cam_jpg_op get_jcomp;
+ cam_jpg_op set_jcomp;
+ cam_qmnu_op querymenu;
+};
+
+/* packet types when moving from iso buf to frame buf */
+#define DISCARD_PACKET 0
+#define FIRST_PACKET 1
+#define INTER_PACKET 2
+#define LAST_PACKET 3
+
+struct gspca_frame {
+ __u8 *data; /* frame buffer */
+ __u8 *data_end; /* end of frame while filling */
+ int vma_use_count;
+ struct v4l2_buffer v4l2_buf;
+};
+
+struct gspca_dev {
+ struct video_device vdev; /* !! must be the first item */
+ struct file_operations fops;
+ struct usb_device *dev;
+ struct file *capt_file; /* file doing video capture */
+
+ struct cam cam; /* device information */
+ const struct sd_desc *sd_desc; /* subdriver description */
+
+ __u8 usb_buf[8]; /* buffer for USB exchanges */
+ struct urb *urb[MAX_NURBS];
+
+ __u8 *frbuf; /* buffer for nframes */
+ struct gspca_frame frame[GSPCA_MAX_FRAMES];
+ __u32 frsz; /* frame size */
+ char nframes; /* number of frames */
+ char fr_i; /* frame being filled */
+ char fr_q; /* next frame to queue */
+ char fr_o; /* next frame to dequeue */
+ signed char fr_queue[GSPCA_MAX_FRAMES]; /* frame queue */
+ char last_packet_type;
+
+ __u8 iface; /* USB interface number */
+ __u8 alt; /* USB alternate setting */
+ __u8 curr_mode; /* current camera mode */
+ __u32 pixfmt; /* current mode parameters */
+ __u16 width;
+ __u16 height;
+
+ atomic_t nevent; /* number of frames done */
+ wait_queue_head_t wq; /* wait queue */
+ struct mutex usb_lock; /* usb exchange protection */
+ struct mutex read_lock; /* read protection */
+ struct mutex queue_lock; /* ISOC queue protection */
+ __u32 sequence; /* frame sequence number */
+ char streaming;
+ char users; /* number of opens */
+ char present; /* device connected */
+ char nbufread; /* number of buffers for read() */
+ char nurbs; /* number of allocated URBs */
+ char memory; /* memory type (V4L2_MEMORY_xxx) */
+ __u8 nbalt; /* number of USB alternate settings */
+};
+
+int gspca_dev_probe(struct usb_interface *intf,
+ const struct usb_device_id *id,
+ const struct sd_desc *sd_desc,
+ int dev_size,
+ struct module *module);
+void gspca_disconnect(struct usb_interface *intf);
+struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
+ int packet_type,
+ struct gspca_frame *frame,
+ const __u8 *data,
+ int len);
+int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
+ int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee);
+#endif /* GSPCAV2_H */
diff --git a/drivers/media/video/gspca/jpeg.h b/drivers/media/video/gspca/jpeg.h
new file mode 100644
index 00000000000..d823b47bd4e
--- /dev/null
+++ b/drivers/media/video/gspca/jpeg.h
@@ -0,0 +1,301 @@
+#ifndef JPEG_H
+#define JPEG_H 1
+/*
+ * Insert a JPEG header at start of frame
+ *
+ * This module is used by the gspca subdrivers.
+ * A special case is done for Conexant webcams.
+ *
+ * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* start of jpeg frame + quantization table */
+static const unsigned char quant[][0x88] = {
+/* index 0 - Q40*/
+ {
+ 0xff, 0xd8, /* jpeg */
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0, /* quantization table part 1 */
+ 20, 14, 15, 18, 15, 13, 20, 18, 16, 18, 23, 21, 20, 24, 30, 50,
+ 33, 30, 28, 28, 30, 61, 44, 46, 36, 50, 73, 64, 76, 75, 71, 64,
+ 70, 69, 80, 90, 115, 98, 80, 85, 109, 86, 69, 70, 100, 136, 101,
+ 109,
+ 119, 123, 129, 130, 129, 78, 96, 141, 151, 140, 125, 150, 115,
+ 126, 129, 124,
+1, /* quantization table part 2 */
+ 21, 23, 23, 30, 26, 30, 59, 33, 33, 59, 124, 83, 70, 83, 124, 124,
+ 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+ 124, 124, 124,
+ 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+ 124, 124, 124,
+ 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+ 124, 124, 124},
+/* index 1 - Q50 */
+ {
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40,
+ 26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60, 57, 51,
+ 56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80, 109, 81, 87,
+ 95, 98, 103, 104, 103, 62, 77, 113, 121, 112, 100, 120, 92, 101,
+ 103, 99,
+1,
+ 17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 66, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99},
+/* index 2 Q60 */
+ {
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 13, 9, 10, 11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32,
+ 21, 19, 18, 18, 19, 39, 28, 30, 23, 32, 46, 41, 49, 48, 46, 41,
+ 45, 44, 51, 58, 74, 62, 51, 54, 70, 55, 44, 45, 64, 87, 65, 70,
+ 76, 78, 82, 83, 82, 50, 62, 90, 97, 90, 80, 96, 74, 81, 82, 79,
+1,
+ 14, 14, 14, 19, 17, 19, 38, 21, 21, 38, 79, 53, 45, 53, 79, 79,
+ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79},
+/* index 3 - Q70 */
+ {
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 10, 7, 7, 8, 7, 6, 10, 8, 8, 8, 11, 10, 10, 11, 14, 24,
+ 16, 14, 13, 13, 14, 29, 21, 22, 17, 24, 35, 31, 37, 36, 34, 31,
+ 34, 33, 38, 43, 55, 47, 38, 41, 52, 41, 33, 34, 48, 65, 49, 52,
+ 57, 59, 62, 62, 62, 37, 46, 68, 73, 67, 60, 72, 55, 61, 62, 59,
+1,
+ 10, 11, 11, 14, 13, 14, 28, 16, 16, 28, 59, 40, 34, 40, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59},
+/* index 4 - Q80 */
+ {
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 6, 4, 5, 6, 5, 4, 6, 6, 5, 6, 7, 7, 6, 8, 10, 16,
+ 10, 10, 9, 9, 10, 20, 14, 15, 12, 16, 23, 20, 24, 24, 23, 20,
+ 22, 22, 26, 29, 37, 31, 26, 27, 35, 28, 22, 22, 32, 44, 32, 35,
+ 38, 39, 41, 42, 41, 25, 31, 45, 48, 45, 40, 48, 37, 40, 41, 40,
+1,
+ 7, 7, 7, 10, 8, 10, 19, 10, 10, 19, 40, 26, 22, 26, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40},
+/* index 5 - Q85 */
+ {
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 5, 3, 4, 4, 4, 3, 5, 4, 4, 4, 5, 5, 5, 6, 7, 12,
+ 8, 7, 7, 7, 7, 15, 11, 11, 9, 12, 17, 15, 18, 18, 17, 15,
+ 17, 17, 19, 22, 28, 23, 19, 20, 26, 21, 17, 17, 24, 33, 24, 26,
+ 29, 29, 31, 31, 31, 19, 23, 34, 36, 34, 30, 36, 28, 30, 31, 30,
+1,
+ 5, 5, 5, 7, 6, 7, 14, 8, 8, 14, 30, 20, 17, 20, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+/* index 6 - 86 */
+{
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 0x04, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x04,
+ 0x04, 0x04, 0x05, 0x05, 0x04, 0x05, 0x07, 0x0B,
+ 0x07, 0x07, 0x06, 0x06, 0x07, 0x0E, 0x0A, 0x0A,
+ 0x08, 0x0B, 0x10, 0x0E, 0x11, 0x11, 0x10, 0x0E,
+ 0x10, 0x0F, 0x12, 0x14, 0x1A, 0x16, 0x12, 0x13,
+ 0x18, 0x13, 0x0F, 0x10, 0x16, 0x1F, 0x17, 0x18,
+ 0x1B, 0x1B, 0x1D, 0x1D, 0x1D, 0x11, 0x16, 0x20,
+ 0x22, 0x1F, 0x1C, 0x22, 0x1A, 0x1C, 0x1D, 0x1C,
+1,
+ 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0D, 0x07,
+ 0x07, 0x0D, 0x1C, 0x12, 0x10, 0x12, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ },
+/* index 7 - 88 */
+{
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x06, 0x0A,
+ 0x06, 0x06, 0x05, 0x05, 0x06, 0x0C, 0x08, 0x09,
+ 0x07, 0x0A, 0x0E, 0x0C, 0x0F, 0x0E, 0x0E, 0x0C,
+ 0x0D, 0x0D, 0x0F, 0x11, 0x16, 0x13, 0x0F, 0x10,
+ 0x15, 0x11, 0x0D, 0x0D, 0x13, 0x1A, 0x13, 0x15,
+ 0x17, 0x18, 0x19, 0x19, 0x19, 0x0F, 0x12, 0x1B,
+ 0x1D, 0x1B, 0x18, 0x1D, 0x16, 0x18, 0x19, 0x18,
+1,
+ 0x04, 0x04, 0x04, 0x06, 0x05, 0x06, 0x0B, 0x06,
+ 0x06, 0x0B, 0x18, 0x10, 0x0D, 0x10, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+},
+/* index 8 - ?? */
+{
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x05,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x05,
+ 0x04, 0x05, 0x07, 0x06, 0x08, 0x08, 0x07, 0x06,
+ 0x07, 0x07, 0x08, 0x09, 0x0C, 0x0A, 0x08, 0x09,
+ 0x0B, 0x09, 0x07, 0x07, 0x0A, 0x0E, 0x0A, 0x0B,
+ 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x08, 0x0A, 0x0E,
+ 0x0F, 0x0E, 0x0D, 0x0F, 0x0C, 0x0D, 0x0D, 0x0C,
+1,
+ 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x06, 0x03,
+ 0x03, 0x06, 0x0C, 0x08, 0x07, 0x08, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
+}
+};
+
+/* huffman table + start of SOF0 */
+static unsigned char huffman[] = {
+ 0xff, 0xc4, 0x01, 0xa2,
+ 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x03,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03,
+ 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00,
+ 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04,
+ 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13,
+ 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81,
+ 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15,
+ 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82,
+ 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
+ 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56,
+ 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
+ 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86,
+ 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95,
+ 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
+ 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
+ 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+ 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+ 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02,
+ 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05,
+ 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
+ 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06,
+ 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
+ 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1,
+ 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62,
+ 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
+ 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,
+ 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
+ 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
+ 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
+ 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3,
+ 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2,
+ 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
+#ifdef CONEX_CAM
+/* the Conexant frames start with SOF0 */
+#else
+ 0xff, 0xc0, 0x00, 0x11, /* SOF0 (start of frame 0 */
+ 0x08, /* data precision */
+#endif
+};
+
+#ifndef CONEX_CAM
+/* variable part:
+ * 0x01, 0xe0, height
+ * 0x02, 0x80, width
+ * 0x03, component number
+ * 0x01,
+ * 0x21, samples Y
+ */
+
+/* end of header */
+static unsigned char eoh[] = {
+ 0x00, /* quant Y */
+ 0x02, 0x11, 0x01, /* samples CbCr - quant CbCr */
+ 0x03, 0x11, 0x01,
+
+ 0xff, 0xda, 0x00, 0x0c, /* SOS (start of scan) */
+ 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+};
+#endif
+
+/* -- output the JPEG header -- */
+static void jpeg_put_header(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame,
+ int qindex,
+ int samplesY)
+{
+#ifndef CONEX_CAM
+ unsigned char tmpbuf[8];
+#endif
+
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ (unsigned char *) quant[qindex], sizeof quant[0]);
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ (unsigned char *) huffman, sizeof huffman);
+#ifndef CONEX_CAM
+ tmpbuf[0] = gspca_dev->height >> 8;
+ tmpbuf[1] = gspca_dev->height & 0xff;
+ tmpbuf[2] = gspca_dev->width >> 8;
+ tmpbuf[3] = gspca_dev->width & 0xff;
+ tmpbuf[4] = 0x03; /* component number */
+ tmpbuf[5] = 0x01; /* first component */
+ tmpbuf[6] = samplesY;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ tmpbuf, 7);
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ eoh, sizeof eoh);
+#endif
+}
+#endif
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
new file mode 100644
index 00000000000..88c2b02f380
--- /dev/null
+++ b/drivers/media/video/gspca/mars.c
@@ -0,0 +1,464 @@
+/*
+ * Mars-Semi MR97311A library
+ * Copyright (C) 2005 <bradlch@hotmail.com>
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "mars"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ char qindex;
+};
+
+/* V4L2 controls supported by the driver */
+static struct ctrl sd_ctrls[] = {
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 589,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+};
+
+/* MI Register table //elvis */
+enum {
+ REG_HW_MI_0,
+ REG_HW_MI_1,
+ REG_HW_MI_2,
+ REG_HW_MI_3,
+ REG_HW_MI_4,
+ REG_HW_MI_5,
+ REG_HW_MI_6,
+ REG_HW_MI_7,
+ REG_HW_MI_9 = 0x09,
+ REG_HW_MI_B = 0x0B,
+ REG_HW_MI_C,
+ REG_HW_MI_D,
+ REG_HW_MI_1E = 0x1E,
+ REG_HW_MI_20 = 0x20,
+ REG_HW_MI_2B = 0x2B,
+ REG_HW_MI_2C,
+ REG_HW_MI_2D,
+ REG_HW_MI_2E,
+ REG_HW_MI_35 = 0x35,
+ REG_HW_MI_5F = 0x5f,
+ REG_HW_MI_60,
+ REG_HW_MI_61,
+ REG_HW_MI_62,
+ REG_HW_MI_63,
+ REG_HW_MI_64,
+ REG_HW_MI_F1 = 0xf1,
+ ATTR_TOTAL_MI_REG = 0xf2
+};
+
+/* the bytes to write are in gspca_dev->usb_buf */
+static int reg_w(struct gspca_dev *gspca_dev,
+ __u16 index, int len)
+{
+ int rc;
+
+ rc = usb_control_msg(gspca_dev->dev,
+ usb_sndbulkpipe(gspca_dev->dev, 4),
+ 0x12,
+ 0xc8, /* ?? */
+ 0, /* value */
+ index, gspca_dev->usb_buf, len, 500);
+ if (rc < 0)
+ PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc);
+ return rc;
+}
+
+static int reg_w_buf(struct gspca_dev *gspca_dev,
+ __u16 index, __u8 *buf, int len)
+{
+ int rc;
+
+ rc = usb_control_msg(gspca_dev->dev,
+ usb_sndbulkpipe(gspca_dev->dev, 4),
+ 0x12,
+ 0xc8, /* ?? */
+ 0, /* value */
+ index, buf, len, 500);
+ if (rc < 0)
+ PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc);
+ return rc;
+}
+
+static void bulk_w(struct gspca_dev *gspca_dev,
+ __u16 *pch,
+ __u16 Address)
+{
+ gspca_dev->usb_buf[0] = 0x1f;
+ gspca_dev->usb_buf[1] = 0; /* control byte */
+ gspca_dev->usb_buf[2] = Address;
+ gspca_dev->usb_buf[3] = *pch >> 8; /* high byte */
+ gspca_dev->usb_buf[4] = *pch; /* low byte */
+
+ reg_w(gspca_dev, Address, 5);
+}
+
+/* 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;
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ sd->qindex = 1; /* set the quantization table */
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ int err_code;
+ __u8 *data;
+ __u16 *MI_buf;
+ int h_size, v_size;
+ int intpipe;
+
+ PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface);
+ if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 8) < 0) {
+ PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error");
+ return;
+ }
+
+ data = gspca_dev->usb_buf;
+ data[0] = 0x01; /* address */
+ data[1] = 0x01;
+
+ err_code = reg_w(gspca_dev, data[0], 2);
+ if (err_code < 0)
+ return;
+
+ /*
+ Initialize the MR97113 chip register
+ */
+ data = kmalloc(16, GFP_KERNEL);
+ data[0] = 0x00; /* address */
+ data[1] = 0x0c | 0x01; /* reg 0 */
+ data[2] = 0x01; /* reg 1 */
+ h_size = gspca_dev->width;
+ v_size = gspca_dev->height;
+ data[3] = h_size / 8; /* h_size , reg 2 */
+ data[4] = v_size / 8; /* v_size , reg 3 */
+ data[5] = 0x30; /* reg 4, MI, PAS5101 :
+ * 0x30 for 24mhz , 0x28 for 12mhz */
+ data[6] = 4; /* reg 5, H start */
+ data[7] = 0xc0; /* reg 6, gamma 1.5 */
+ data[8] = 3; /* reg 7, V start */
+/* if (h_size == 320 ) */
+/* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */
+/* else */
+ data[9] = 0x52; /* reg 8, 24MHz, no scale down */
+ data[10] = 0x5d; /* reg 9, I2C device address
+ * [for PAS5101 (0x40)] [for MI (0x5d)] */
+
+ err_code = reg_w_buf(gspca_dev, data[0], data, 11);
+ kfree(data);
+ if (err_code < 0)
+ return;
+
+ data = gspca_dev->usb_buf;
+ data[0] = 0x23; /* address */
+ data[1] = 0x09; /* reg 35, append frame header */
+
+ err_code = reg_w(gspca_dev, data[0], 2);
+ if (err_code < 0)
+ return;
+
+ data[0] = 0x3c; /* address */
+/* if (gspca_dev->width == 1280) */
+/* data[1] = 200; * reg 60, pc-cam frame size
+ * (unit: 4KB) 800KB */
+/* else */
+ data[1] = 50; /* 50 reg 60, pc-cam frame size
+ * (unit: 4KB) 200KB */
+ err_code = reg_w(gspca_dev, data[0], 2);
+ if (err_code < 0)
+ return;
+
+ if (0) { /* fixed dark-gain */
+ data[1] = 0; /* reg 94, Y Gain (1.75) */
+ data[2] = 0; /* reg 95, UV Gain (1.75) */
+ data[3] = 0x3f; /* reg 96, Y Gain/UV Gain/disable
+ * auto dark-gain */
+ data[4] = 0; /* reg 97, set fixed dark level */
+ data[5] = 0; /* reg 98, don't care */
+ } else { /* auto dark-gain */
+ data[1] = 0; /* reg 94, Y Gain (auto) */
+ data[2] = 0; /* reg 95, UV Gain (1.75) */
+ data[3] = 0x78; /* reg 96, Y Gain/UV Gain/disable
+ * auto dark-gain */
+ switch (gspca_dev->width) {
+/* case 1280: */
+/* data[4] = 154;
+ * reg 97, %3 shadow point (unit: 256 pixel) */
+/* data[5] = 51;
+ * reg 98, %1 highlight point
+ * (uint: 256 pixel) */
+/* break; */
+ default:
+/* case 640: */
+ data[4] = 36; /* reg 97, %3 shadow point
+ * (unit: 256 pixel) */
+ data[5] = 12; /* reg 98, %1 highlight point
+ * (uint: 256 pixel) */
+ break;
+ case 320:
+ data[4] = 9; /* reg 97, %3 shadow point
+ * (unit: 256 pixel) */
+ data[5] = 3; /* reg 98, %1 highlight point
+ * (uint: 256 pixel) */
+ break;
+ }
+ }
+ /* auto dark-gain */
+ data[0] = 0x5e; /* address */
+
+ err_code = reg_w(gspca_dev, data[0], 6);
+ if (err_code < 0)
+ return;
+
+ data[0] = 0x67;
+ data[1] = 0x13; /* reg 103, first pixel B, disable sharpness */
+ err_code = reg_w(gspca_dev, data[0], 2);
+ if (err_code < 0)
+ return;
+
+ /*
+ * initialize the value of MI sensor...
+ */
+ MI_buf = kzalloc(ATTR_TOTAL_MI_REG * sizeof *MI_buf, GFP_KERNEL);
+ MI_buf[REG_HW_MI_1] = 0x000a;
+ MI_buf[REG_HW_MI_2] = 0x000c;
+ MI_buf[REG_HW_MI_3] = 0x0405;
+ MI_buf[REG_HW_MI_4] = 0x0507;
+ /* mi_Attr_Reg_[REG_HW_MI_5] = 0x01ff;//13 */
+ MI_buf[REG_HW_MI_5] = 0x0013; /* 13 */
+ MI_buf[REG_HW_MI_6] = 0x001f; /* vertical blanking */
+ /* mi_Attr_Reg_[REG_HW_MI_6] = 0x0400; // vertical blanking */
+ MI_buf[REG_HW_MI_7] = 0x0002;
+ /* mi_Attr_Reg_[REG_HW_MI_9] = 0x015f; */
+ /* mi_Attr_Reg_[REG_HW_MI_9] = 0x030f; */
+ MI_buf[REG_HW_MI_9] = 0x0374;
+ MI_buf[REG_HW_MI_B] = 0x0000;
+ MI_buf[REG_HW_MI_C] = 0x0000;
+ MI_buf[REG_HW_MI_D] = 0x0000;
+ MI_buf[REG_HW_MI_1E] = 0x8000;
+/* mi_Attr_Reg_[REG_HW_MI_20] = 0x1104; */
+ MI_buf[REG_HW_MI_20] = 0x1104; /* 0x111c; */
+ MI_buf[REG_HW_MI_2B] = 0x0008;
+/* mi_Attr_Reg_[REG_HW_MI_2C] = 0x000f; */
+ MI_buf[REG_HW_MI_2C] = 0x001f; /* lita suggest */
+ MI_buf[REG_HW_MI_2D] = 0x0008;
+ MI_buf[REG_HW_MI_2E] = 0x0008;
+ MI_buf[REG_HW_MI_35] = 0x0051;
+ MI_buf[REG_HW_MI_5F] = 0x0904; /* fail to write */
+ MI_buf[REG_HW_MI_60] = 0x0000;
+ MI_buf[REG_HW_MI_61] = 0x0000;
+ MI_buf[REG_HW_MI_62] = 0x0498;
+ MI_buf[REG_HW_MI_63] = 0x0000;
+ MI_buf[REG_HW_MI_64] = 0x0000;
+ MI_buf[REG_HW_MI_F1] = 0x0001;
+ /* changing while setting up the different value of dx/dy */
+
+ if (gspca_dev->width != 1280) {
+ MI_buf[0x01] = 0x010a;
+ MI_buf[0x02] = 0x014c;
+ MI_buf[0x03] = 0x01e5;
+ MI_buf[0x04] = 0x0287;
+ }
+ MI_buf[0x20] = 0x1104;
+
+ bulk_w(gspca_dev, MI_buf + 1, 1);
+ bulk_w(gspca_dev, MI_buf + 2, 2);
+ bulk_w(gspca_dev, MI_buf + 3, 3);
+ bulk_w(gspca_dev, MI_buf + 4, 4);
+ bulk_w(gspca_dev, MI_buf + 5, 5);
+ bulk_w(gspca_dev, MI_buf + 6, 6);
+ bulk_w(gspca_dev, MI_buf + 7, 7);
+ bulk_w(gspca_dev, MI_buf + 9, 9);
+ bulk_w(gspca_dev, MI_buf + 0x0b, 0x0b);
+ bulk_w(gspca_dev, MI_buf + 0x0c, 0x0c);
+ bulk_w(gspca_dev, MI_buf + 0x0d, 0x0d);
+ bulk_w(gspca_dev, MI_buf + 0x1e, 0x1e);
+ bulk_w(gspca_dev, MI_buf + 0x20, 0x20);
+ bulk_w(gspca_dev, MI_buf + 0x2b, 0x2b);
+ bulk_w(gspca_dev, MI_buf + 0x2c, 0x2c);
+ bulk_w(gspca_dev, MI_buf + 0x2d, 0x2d);
+ bulk_w(gspca_dev, MI_buf + 0x2e, 0x2e);
+ bulk_w(gspca_dev, MI_buf + 0x35, 0x35);
+ bulk_w(gspca_dev, MI_buf + 0x5f, 0x5f);
+ bulk_w(gspca_dev, MI_buf + 0x60, 0x60);
+ bulk_w(gspca_dev, MI_buf + 0x61, 0x61);
+ bulk_w(gspca_dev, MI_buf + 0x62, 0x62);
+ bulk_w(gspca_dev, MI_buf + 0x63, 0x63);
+ bulk_w(gspca_dev, MI_buf + 0x64, 0x64);
+ bulk_w(gspca_dev, MI_buf + 0xf1, 0xf1);
+ kfree(MI_buf);
+
+ intpipe = usb_sndintpipe(gspca_dev->dev, 0);
+ err_code = usb_clear_halt(gspca_dev->dev, intpipe);
+
+ data[0] = 0x00;
+ data[1] = 0x4d; /* ISOC transfering enable... */
+ reg_w(gspca_dev, data[0], 2);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ int result;
+
+ gspca_dev->usb_buf[0] = 1;
+ gspca_dev->usb_buf[1] = 0;
+ result = reg_w(gspca_dev, gspca_dev->usb_buf[0], 2);
+ if (result < 0)
+ PDEBUG(D_ERR, "Camera Stop failed");
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+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;
+ int p;
+
+ if (len < 6) {
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ for (p = 0; p < len - 6; p++) {
+ if (data[0 + p] == 0xff
+ && data[1 + p] == 0xff
+ && data[2 + p] == 0x00
+ && data[3 + p] == 0xff
+ && data[4 + p] == 0x96) {
+ if (data[5 + p] == 0x64
+ || data[5 + p] == 0x65
+ || data[5 + p] == 0x66
+ || data[5 + p] == 0x67) {
+ PDEBUG(D_PACK, "sof offset: %d leng: %d",
+ p, len);
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET,
+ frame, data, 0);
+
+ /* put the JPEG header */
+ jpeg_put_header(gspca_dev, frame,
+ sd->qindex, 0x21);
+ data += 16;
+ len -= 16;
+ break;
+ }
+ }
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x093a, 0x050f), DVNM("Mars-Semi Pc-Camera")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
new file mode 100644
index 00000000000..08d99c3b78e
--- /dev/null
+++ b/drivers/media/video/gspca/ov519.c
@@ -0,0 +1,2186 @@
+/**
+ * OV519 driver
+ *
+ * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * (This module is adapted from the ov51x-jpeg package)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#define MODULE_NAME "ov519"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("OV519 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* global parameters */
+static int frame_rate;
+
+/* Number of times to retry a failed I2C transaction. Increase this if you
+ * are getting "Failed to read sensor ID..." */
+static int i2c_detect_tries = 10;
+
+/* ov519 device descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ /* Determined by sensor type */
+ short maxwidth;
+ short maxheight;
+
+ unsigned char primary_i2c_slave; /* I2C write id of sensor */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+
+ char compress; /* Should the next frame be compressed? */
+ char compress_inited; /* Are compression params uploaded? */
+ char stopped; /* Streaming is temporarily paused */
+
+ char frame_rate; /* current Framerate (OV519 only) */
+ char clockdiv; /* clockdiv override for OV519 only */
+
+ char sensor; /* Type of image sensor chip (SEN_*) */
+#define SEN_UNKNOWN 0
+#define SEN_OV6620 1
+#define SEN_OV6630 2
+#define SEN_OV7610 3
+#define SEN_OV7620 4
+#define SEN_OV7630 5
+#define SEN_OV7640 6
+#define SEN_OV7670 7
+#define SEN_OV76BE 8
+#define SEN_OV8610 9
+
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_COLOR 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 589,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 8 + 589,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 8 + 589,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/* OV519 Camera interface register numbers */
+#define OV519_CAM_H_SIZE 0x10
+#define OV519_CAM_V_SIZE 0x11
+#define OV519_CAM_X_OFFSETL 0x12
+#define OV519_CAM_X_OFFSETH 0x13
+#define OV519_CAM_Y_OFFSETL 0x14
+#define OV519_CAM_Y_OFFSETH 0x15
+#define OV519_CAM_DIVIDER 0x16
+#define OV519_CAM_DFR 0x20
+#define OV519_CAM_FORMAT 0x25
+
+/* OV519 System Controller register numbers */
+#define OV519_SYS_RESET1 0x51
+#define OV519_SYS_EN_CLK1 0x54
+
+#define OV519_GPIO_DATA_OUT0 0x71
+#define OV519_GPIO_IO_CTRL0 0x72
+
+#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */
+
+/* I2C registers */
+#define R51x_I2C_W_SID 0x41
+#define R51x_I2C_SADDR_3 0x42
+#define R51x_I2C_SADDR_2 0x43
+#define R51x_I2C_R_SID 0x44
+#define R51x_I2C_DATA 0x45
+#define R518_I2C_CTL 0x47 /* OV518(+) only */
+
+/* I2C ADDRESSES */
+#define OV7xx0_SID 0x42
+#define OV8xx0_SID 0xa0
+#define OV6xx0_SID 0xc0
+
+/* OV7610 registers */
+#define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */
+#define OV7610_REG_SAT 0x03 /* saturation */
+#define OV8610_REG_HUE 0x04 /* 04 reserved */
+#define OV7610_REG_CNT 0x05 /* Y contrast */
+#define OV7610_REG_BRT 0x06 /* Y brightness */
+#define OV7610_REG_COM_C 0x14 /* misc common regs */
+#define OV7610_REG_ID_HIGH 0x1c /* manufacturer ID MSB */
+#define OV7610_REG_ID_LOW 0x1d /* manufacturer ID LSB */
+#define OV7610_REG_COM_I 0x29 /* misc settings */
+
+/* OV7670 registers */
+#define OV7670_REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
+#define OV7670_REG_BLUE 0x01 /* blue gain */
+#define OV7670_REG_RED 0x02 /* red gain */
+#define OV7670_REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */
+#define OV7670_REG_COM1 0x04 /* Control 1 */
+#define OV7670_REG_AECHH 0x07 /* AEC MS 5 bits */
+#define OV7670_REG_COM3 0x0c /* Control 3 */
+#define OV7670_REG_COM4 0x0d /* Control 4 */
+#define OV7670_REG_COM5 0x0e /* All "reserved" */
+#define OV7670_REG_COM6 0x0f /* Control 6 */
+#define OV7670_REG_AECH 0x10 /* More bits of AEC value */
+#define OV7670_REG_CLKRC 0x11 /* Clock control */
+#define OV7670_REG_COM7 0x12 /* Control 7 */
+#define OV7670_COM7_FMT_VGA 0x00
+#define OV7670_COM7_YUV 0x00 /* YUV */
+#define OV7670_COM7_FMT_QVGA 0x10 /* QVGA format */
+#define OV7670_COM7_FMT_MASK 0x38
+#define OV7670_COM7_RESET 0x80 /* Register reset */
+#define OV7670_REG_COM8 0x13 /* Control 8 */
+#define OV7670_COM8_AEC 0x01 /* Auto exposure enable */
+#define OV7670_COM8_AWB 0x02 /* White balance enable */
+#define OV7670_COM8_AGC 0x04 /* Auto gain enable */
+#define OV7670_COM8_BFILT 0x20 /* Band filter enable */
+#define OV7670_COM8_AECSTEP 0x40 /* Unlimited AEC step size */
+#define OV7670_COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */
+#define OV7670_REG_COM9 0x14 /* Control 9 - gain ceiling */
+#define OV7670_REG_COM10 0x15 /* Control 10 */
+#define OV7670_REG_HSTART 0x17 /* Horiz start high bits */
+#define OV7670_REG_HSTOP 0x18 /* Horiz stop high bits */
+#define OV7670_REG_VSTART 0x19 /* Vert start high bits */
+#define OV7670_REG_VSTOP 0x1a /* Vert stop high bits */
+#define OV7670_REG_MVFP 0x1e /* Mirror / vflip */
+#define OV7670_MVFP_MIRROR 0x20 /* Mirror image */
+#define OV7670_REG_AEW 0x24 /* AGC upper limit */
+#define OV7670_REG_AEB 0x25 /* AGC lower limit */
+#define OV7670_REG_VPT 0x26 /* AGC/AEC fast mode op region */
+#define OV7670_REG_HREF 0x32 /* HREF pieces */
+#define OV7670_REG_TSLB 0x3a /* lots of stuff */
+#define OV7670_REG_COM11 0x3b /* Control 11 */
+#define OV7670_COM11_EXP 0x02
+#define OV7670_COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */
+#define OV7670_REG_COM12 0x3c /* Control 12 */
+#define OV7670_REG_COM13 0x3d /* Control 13 */
+#define OV7670_COM13_GAMMA 0x80 /* Gamma enable */
+#define OV7670_COM13_UVSAT 0x40 /* UV saturation auto adjustment */
+#define OV7670_REG_COM14 0x3e /* Control 14 */
+#define OV7670_REG_EDGE 0x3f /* Edge enhancement factor */
+#define OV7670_REG_COM15 0x40 /* Control 15 */
+#define OV7670_COM15_R00FF 0xc0 /* 00 to FF */
+#define OV7670_REG_COM16 0x41 /* Control 16 */
+#define OV7670_COM16_AWBGAIN 0x08 /* AWB gain enable */
+#define OV7670_REG_BRIGHT 0x55 /* Brightness */
+#define OV7670_REG_CONTRAS 0x56 /* Contrast control */
+#define OV7670_REG_GFIX 0x69 /* Fix gain control */
+#define OV7670_REG_RGB444 0x8c /* RGB 444 control */
+#define OV7670_REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */
+#define OV7670_REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */
+#define OV7670_REG_BD50MAX 0xa5 /* 50hz banding step limit */
+#define OV7670_REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */
+#define OV7670_REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */
+#define OV7670_REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */
+#define OV7670_REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */
+#define OV7670_REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */
+#define OV7670_REG_BD60MAX 0xab /* 60hz banding step limit */
+
+struct ovsensor_window {
+ short x;
+ short y;
+ short width;
+ short height;
+/* int format; */
+ short quarter; /* Scale width and height down 2x */
+ short clockdiv; /* Clock divisor setting */
+};
+
+static unsigned char ov7670_abs_to_sm(unsigned char v)
+{
+ if (v > 127)
+ return v & 0x7f;
+ return (128 - v) | 0x80;
+}
+
+/* Write a OV519 register */
+static int reg_w(struct sd *sd, __u16 index, __u8 value)
+{
+ int ret;
+
+ 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) */
+ 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;
+}
+
+/* Read from a OV519 register */
+/* returns: negative is error, pos or zero is data */
+static int reg_r(struct sd *sd, __u16 index)
+{
+ int ret;
+
+ ret = usb_control_msg(sd->gspca_dev.dev,
+ usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
+ 1, /* REQ_IO */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, index, sd->gspca_dev.usb_buf, 1, 500);
+
+ if (ret >= 0)
+ ret = sd->gspca_dev.usb_buf[0];
+ else
+ PDEBUG(D_ERR, "Read reg [0x%02x] failed", index);
+ return ret;
+}
+
+/* Read 8 values from a OV519 register */
+static int reg_r8(struct sd *sd,
+ __u16 index)
+{
+ int ret;
+
+ ret = usb_control_msg(sd->gspca_dev.dev,
+ usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
+ 1, /* REQ_IO */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, index, sd->gspca_dev.usb_buf, 8, 500);
+
+ if (ret >= 0)
+ ret = sd->gspca_dev.usb_buf[0];
+ else
+ PDEBUG(D_ERR, "Read reg 8 [0x%02x] failed", index);
+ return ret;
+}
+
+/*
+ * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless
+ * of their respective state in "value".
+ */
+static int reg_w_mask(struct sd *sd,
+ __u16 index,
+ __u8 value,
+ __u8 mask)
+{
+ int ret;
+ __u8 oldval;
+
+ if (mask != 0xff) {
+ value &= mask; /* Enforce mask on value */
+ ret = reg_r(sd, index);
+ if (ret < 0)
+ return ret;
+
+ oldval = ret & ~mask; /* Clear the masked bits */
+ value |= oldval; /* Set the desired bits */
+ }
+ return reg_w(sd, index, value);
+}
+
+/*
+ * The OV518 I2C I/O procedure is different, hence, this function.
+ * This is normally only called from i2c_w(). Note that this function
+ * always succeeds regardless of whether the sensor is present and working.
+ */
+static int i2c_w(struct sd *sd,
+ __u8 reg,
+ __u8 value)
+{
+ int rc;
+
+ PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+
+ /* Select camera register */
+ rc = reg_w(sd, R51x_I2C_SADDR_3, reg);
+ if (rc < 0)
+ return rc;
+
+ /* Write "value" to I2C data port of OV511 */
+ rc = reg_w(sd, R51x_I2C_DATA, value);
+ if (rc < 0)
+ return rc;
+
+ /* Initiate 3-byte write cycle */
+ rc = reg_w(sd, R518_I2C_CTL, 0x01);
+
+ /* wait for write complete */
+ msleep(4);
+ if (rc < 0)
+ return rc;
+ return reg_r8(sd, R518_I2C_CTL);
+}
+
+/*
+ * returns: negative is error, pos or zero is data
+ *
+ * The OV518 I2C I/O procedure is different, hence, this function.
+ * This is normally only called from i2c_r(). Note that this function
+ * always succeeds regardless of whether the sensor is present and working.
+ */
+static int i2c_r(struct sd *sd, __u8 reg)
+{
+ int rc, value;
+
+ /* Select camera register */
+ rc = reg_w(sd, R51x_I2C_SADDR_2, reg);
+ if (rc < 0)
+ return rc;
+
+ /* Initiate 2-byte write cycle */
+ rc = reg_w(sd, R518_I2C_CTL, 0x03);
+ if (rc < 0)
+ return rc;
+
+ /* Initiate 2-byte read cycle */
+ rc = reg_w(sd, R518_I2C_CTL, 0x05);
+ if (rc < 0)
+ return rc;
+ value = reg_r(sd, R51x_I2C_DATA);
+ PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
+ return value;
+}
+
+/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless
+ * of their respective state in "value".
+ */
+static int i2c_w_mask(struct sd *sd,
+ __u8 reg,
+ __u8 value,
+ __u8 mask)
+{
+ int rc;
+ __u8 oldval;
+
+ value &= mask; /* Enforce mask on value */
+ rc = i2c_r(sd, reg);
+ if (rc < 0)
+ return rc;
+ oldval = rc & ~mask; /* Clear the masked bits */
+ value |= oldval; /* Set the desired bits */
+ return i2c_w(sd, reg, value);
+}
+
+/* Temporarily stops OV511 from functioning. Must do this before changing
+ * registers while the camera is streaming */
+static inline int ov51x_stop(struct sd *sd)
+{
+ PDEBUG(D_STREAM, "stopping");
+ sd->stopped = 1;
+ return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+}
+
+/* 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)
+{
+ PDEBUG(D_STREAM, "restarting");
+ if (!sd->stopped)
+ return 0;
+ sd->stopped = 0;
+
+ /* Reinitialize the stream */
+ return reg_w(sd, OV519_SYS_RESET1, 0x00);
+}
+
+/* This does an initial reset of an OmniVision sensor and ensures that I2C
+ * is synchronized. Returns <0 on failure.
+ */
+static int init_ov_sensor(struct sd *sd)
+{
+ int i, success;
+
+ /* Reset the sensor */
+ if (i2c_w(sd, 0x12, 0x80) < 0)
+ return -EIO;
+
+ /* Wait for it to initialize */
+ msleep(150);
+
+ for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
+ if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f &&
+ i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) {
+ success = 1;
+ continue;
+ }
+
+ /* Reset the sensor */
+ if (i2c_w(sd, 0x12, 0x80) < 0)
+ return -EIO;
+ /* Wait for it to initialize */
+ msleep(150);
+ /* Dummy read to sync I2C */
+ if (i2c_r(sd, 0x00) < 0)
+ return -EIO;
+ }
+ if (!success)
+ return -EIO;
+ PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i);
+ return 0;
+}
+
+/* Switch on standard JPEG compression. Returns 0 for success. */
+static int ov519_init_compression(struct sd *sd)
+{
+ if (!sd->compress_inited) {
+ if (reg_w_mask(sd, OV519_SYS_EN_CLK1, 1 << 2, 1 << 2) < 0) {
+ PDEBUG(D_ERR, "Error switching to compressed mode");
+ return -EIO;
+ }
+ sd->compress_inited = 1;
+ }
+ return 0;
+}
+
+/* Set the read and write slave IDs. The "slave" argument is the write slave,
+ * and the read slave will be set to (slave + 1).
+ * This should not be called from outside the i2c I/O functions.
+ * Sets I2C read and write slave IDs. Returns <0 for error
+ */
+static int ov51x_set_slave_ids(struct sd *sd,
+ __u8 slave)
+{
+ int rc;
+
+ rc = reg_w(sd, R51x_I2C_W_SID, slave);
+ if (rc < 0)
+ return rc;
+ return reg_w(sd, R51x_I2C_R_SID, slave + 1);
+}
+
+struct ov_regvals {
+ __u8 reg;
+ __u8 val;
+};
+struct ov_i2c_regvals {
+ __u8 reg;
+ __u8 val;
+};
+
+static int write_regvals(struct sd *sd,
+ const struct ov_regvals *regvals,
+ int n)
+{
+ int rc;
+
+ while (--n >= 0) {
+ rc = reg_w(sd, regvals->reg, regvals->val);
+ if (rc < 0)
+ return rc;
+ regvals++;
+ }
+ return 0;
+}
+
+static int write_i2c_regvals(struct sd *sd,
+ const struct ov_i2c_regvals *regvals,
+ int n)
+{
+ int rc;
+
+ while (--n >= 0) {
+ rc = i2c_w(sd, regvals->reg, regvals->val);
+ if (rc < 0)
+ return rc;
+ regvals++;
+ }
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * OV511 and sensor configuration
+ *
+ ***************************************************************************/
+
+/* This initializes the OV8110, OV8610 sensor. The OV8110 uses
+ * the same register settings as the OV8610, since they are very similar.
+ */
+static int ov8xx0_configure(struct sd *sd)
+{
+ int rc;
+ static const struct ov_i2c_regvals norm_8610[] = {
+ { 0x12, 0x80 },
+ { 0x00, 0x00 },
+ { 0x01, 0x80 },
+ { 0x02, 0x80 },
+ { 0x03, 0xc0 },
+ { 0x04, 0x30 },
+ { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
+ { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
+ { 0x0a, 0x86 },
+ { 0x0b, 0xb0 },
+ { 0x0c, 0x20 },
+ { 0x0d, 0x20 },
+ { 0x11, 0x01 },
+ { 0x12, 0x25 },
+ { 0x13, 0x01 },
+ { 0x14, 0x04 },
+ { 0x15, 0x01 }, /* Lin and Win think different about UV order */
+ { 0x16, 0x03 },
+ { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
+ { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
+ { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
+ { 0x1a, 0xf5 },
+ { 0x1b, 0x00 },
+ { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
+ { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
+ { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
+ { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
+ { 0x26, 0xa2 },
+ { 0x27, 0xea },
+ { 0x28, 0x00 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x80 },
+ { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
+ { 0x2c, 0xac },
+ { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
+ { 0x2e, 0x80 },
+ { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
+ { 0x4c, 0x00 },
+ { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
+ { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
+ { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
+ { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
+ { 0x63, 0xff },
+ { 0x64, 0x53 }, /* new windrv 090403 says 0x57,
+ * maybe thats wrong */
+ { 0x65, 0x00 },
+ { 0x66, 0x55 },
+ { 0x67, 0xb0 },
+ { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
+ { 0x69, 0x02 },
+ { 0x6a, 0x22 },
+ { 0x6b, 0x00 },
+ { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
+ deleting bit7 colors the first images red */
+ { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
+ { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
+ { 0x6f, 0x01 },
+ { 0x70, 0x8b },
+ { 0x71, 0x00 },
+ { 0x72, 0x14 },
+ { 0x73, 0x54 },
+ { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
+ { 0x75, 0x0e },
+ { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
+ { 0x77, 0xff },
+ { 0x78, 0x80 },
+ { 0x79, 0x80 },
+ { 0x7a, 0x80 },
+ { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
+ { 0x7c, 0x00 },
+ { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
+ { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
+ { 0x7f, 0xfb },
+ { 0x80, 0x28 },
+ { 0x81, 0x00 },
+ { 0x82, 0x23 },
+ { 0x83, 0x0b },
+ { 0x84, 0x00 },
+ { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
+ { 0x86, 0xc9 },
+ { 0x87, 0x00 },
+ { 0x88, 0x00 },
+ { 0x89, 0x01 },
+ { 0x12, 0x20 },
+ { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
+ };
+
+ PDEBUG(D_PROBE, "starting ov8xx0 configuration");
+
+ if (init_ov_sensor(sd) < 0)
+ PDEBUG(D_ERR|D_PROBE, "Failed to read sensor ID");
+ else
+ PDEBUG(D_PROBE, "OV86x0 initialized");
+
+ /* Detect sensor (sub)type */
+ rc = i2c_r(sd, OV7610_REG_COM_I);
+ if (rc < 0) {
+ PDEBUG(D_ERR, "Error detecting sensor type");
+ return -1;
+ }
+ if ((rc & 3) == 1) {
+ PDEBUG(D_PROBE, "Sensor is an OV8610");
+ sd->sensor = SEN_OV8610;
+ } else {
+ PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
+ return -1;
+ }
+ PDEBUG(D_PROBE, "Writing 8610 registers");
+ if (write_i2c_regvals(sd,
+ norm_8610,
+ sizeof norm_8610 / sizeof norm_8610[0]))
+ return -1;
+
+ /* Set sensor-specific vars */
+ sd->maxwidth = 640;
+ sd->maxheight = 480;
+ return 0;
+}
+
+/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
+ * the same register settings as the OV7610, since they are very similar.
+ */
+static int ov7xx0_configure(struct sd *sd)
+{
+ int rc, high, low;
+
+ /* Lawrence Glaister <lg@jfm.bc.ca> reports:
+ *
+ * Register 0x0f in the 7610 has the following effects:
+ *
+ * 0x85 (AEC method 1): Best overall, good contrast range
+ * 0x45 (AEC method 2): Very overexposed
+ * 0xa5 (spec sheet default): Ok, but the black level is
+ * shifted resulting in loss of contrast
+ * 0x05 (old driver setting): very overexposed, too much
+ * contrast
+ */
+ static const struct ov_i2c_regvals norm_7610[] = {
+ { 0x10, 0xff },
+ { 0x16, 0x06 },
+ { 0x28, 0x24 },
+ { 0x2b, 0xac },
+ { 0x12, 0x00 },
+ { 0x38, 0x81 },
+ { 0x28, 0x24 }, /* 0c */
+ { 0x0f, 0x85 }, /* lg's setting */
+ { 0x15, 0x01 },
+ { 0x20, 0x1c },
+ { 0x23, 0x2a },
+ { 0x24, 0x10 },
+ { 0x25, 0x8a },
+ { 0x26, 0xa2 },
+ { 0x27, 0xc2 },
+ { 0x2a, 0x04 },
+ { 0x2c, 0xfe },
+ { 0x2d, 0x93 },
+ { 0x30, 0x71 },
+ { 0x31, 0x60 },
+ { 0x32, 0x26 },
+ { 0x33, 0x20 },
+ { 0x34, 0x48 },
+ { 0x12, 0x24 },
+ { 0x11, 0x01 },
+ { 0x0c, 0x24 },
+ { 0x0d, 0x24 },
+ };
+
+ static const struct ov_i2c_regvals norm_7620[] = {
+ { 0x00, 0x00 }, /* gain */
+ { 0x01, 0x80 }, /* blue gain */
+ { 0x02, 0x80 }, /* red gain */
+ { 0x03, 0xc0 }, /* OV7670_REG_VREF */
+ { 0x06, 0x60 },
+ { 0x07, 0x00 },
+ { 0x0c, 0x24 },
+ { 0x0c, 0x24 },
+ { 0x0d, 0x24 },
+ { 0x11, 0x01 },
+ { 0x12, 0x24 },
+ { 0x13, 0x01 },
+ { 0x14, 0x84 },
+ { 0x15, 0x01 },
+ { 0x16, 0x03 },
+ { 0x17, 0x2f },
+ { 0x18, 0xcf },
+ { 0x19, 0x06 },
+ { 0x1a, 0xf5 },
+ { 0x1b, 0x00 },
+ { 0x20, 0x18 },
+ { 0x21, 0x80 },
+ { 0x22, 0x80 },
+ { 0x23, 0x00 },
+ { 0x26, 0xa2 },
+ { 0x27, 0xea },
+ { 0x28, 0x20 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x10 },
+ { 0x2b, 0x00 },
+ { 0x2c, 0x88 },
+ { 0x2d, 0x91 },
+ { 0x2e, 0x80 },
+ { 0x2f, 0x44 },
+ { 0x60, 0x27 },
+ { 0x61, 0x02 },
+ { 0x62, 0x5f },
+ { 0x63, 0xd5 },
+ { 0x64, 0x57 },
+ { 0x65, 0x83 },
+ { 0x66, 0x55 },
+ { 0x67, 0x92 },
+ { 0x68, 0xcf },
+ { 0x69, 0x76 },
+ { 0x6a, 0x22 },
+ { 0x6b, 0x00 },
+ { 0x6c, 0x02 },
+ { 0x6d, 0x44 },
+ { 0x6e, 0x80 },
+ { 0x6f, 0x1d },
+ { 0x70, 0x8b },
+ { 0x71, 0x00 },
+ { 0x72, 0x14 },
+ { 0x73, 0x54 },
+ { 0x74, 0x00 },
+ { 0x75, 0x8e },
+ { 0x76, 0x00 },
+ { 0x77, 0xff },
+ { 0x78, 0x80 },
+ { 0x79, 0x80 },
+ { 0x7a, 0x80 },
+ { 0x7b, 0xe2 },
+ { 0x7c, 0x00 },
+ };
+
+ /* 7640 and 7648. The defaults should be OK for most registers. */
+ static const struct ov_i2c_regvals norm_7640[] = {
+ { 0x12, 0x80 },
+ { 0x12, 0x14 },
+ };
+
+ /* 7670. Defaults taken from OmniVision provided data,
+ * as provided by Jonathan Corbet of OLPC */
+ static const struct ov_i2c_regvals norm_7670[] = {
+ { OV7670_REG_COM7, OV7670_COM7_RESET },
+ { OV7670_REG_TSLB, 0x04 }, /* OV */
+ { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
+ { OV7670_REG_CLKRC, 0x1 },
+ /*
+ * Set the hardware window. These values from OV don't entirely
+ * make sense - hstop is less than hstart. But they work...
+ */
+ { OV7670_REG_HSTART, 0x13 }, { OV7670_REG_HSTOP, 0x01 },
+ { OV7670_REG_HREF, 0xb6 }, { OV7670_REG_VSTART, 0x02 },
+ { OV7670_REG_VSTOP, 0x7a }, { OV7670_REG_VREF, 0x0a },
+
+ { OV7670_REG_COM3, 0 }, { OV7670_REG_COM14, 0 },
+ /* Mystery scaling numbers */
+ { 0x70, 0x3a }, { 0x71, 0x35 },
+ { 0x72, 0x11 }, { 0x73, 0xf0 },
+ { 0xa2, 0x02 },
+/* jfm */
+/* { OV7670_REG_COM10, 0x0 }, */
+
+ /* Gamma curve values */
+ { 0x7a, 0x20 },
+/* jfm:win 7b=1c */
+ { 0x7b, 0x10 },
+/* jfm:win 7c=28 */
+ { 0x7c, 0x1e },
+/* jfm:win 7d=3c */
+ { 0x7d, 0x35 },
+ { 0x7e, 0x5a }, { 0x7f, 0x69 },
+ { 0x80, 0x76 }, { 0x81, 0x80 },
+ { 0x82, 0x88 }, { 0x83, 0x8f },
+ { 0x84, 0x96 }, { 0x85, 0xa3 },
+ { 0x86, 0xaf }, { 0x87, 0xc4 },
+ { 0x88, 0xd7 }, { 0x89, 0xe8 },
+
+ /* AGC and AEC parameters. Note we start by disabling those features,
+ then turn them only after tweaking the values. */
+ { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ | OV7670_COM8_AECSTEP
+ | OV7670_COM8_BFILT },
+ { OV7670_REG_GAIN, 0 }, { OV7670_REG_AECH, 0 },
+ { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
+/* jfm:win 14=38 */
+ { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+ { OV7670_REG_BD50MAX, 0x05 }, { OV7670_REG_BD60MAX, 0x07 },
+ { OV7670_REG_AEW, 0x95 }, { OV7670_REG_AEB, 0x33 },
+ { OV7670_REG_VPT, 0xe3 }, { OV7670_REG_HAECC1, 0x78 },
+ { OV7670_REG_HAECC2, 0x68 },
+/* jfm:win a1=0b */
+ { 0xa1, 0x03 }, /* magic */
+ { OV7670_REG_HAECC3, 0xd8 }, { OV7670_REG_HAECC4, 0xd8 },
+ { OV7670_REG_HAECC5, 0xf0 }, { OV7670_REG_HAECC6, 0x90 },
+ { OV7670_REG_HAECC7, 0x94 },
+ { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ | OV7670_COM8_AECSTEP
+ | OV7670_COM8_BFILT
+ | OV7670_COM8_AGC
+ | OV7670_COM8_AEC },
+
+ /* Almost all of these are magic "reserved" values. */
+ { OV7670_REG_COM5, 0x61 }, { OV7670_REG_COM6, 0x4b },
+ { 0x16, 0x02 },
+/* jfm */
+/* { OV7670_REG_MVFP, 0x07|OV7670_MVFP_MIRROR }, */
+ { OV7670_REG_MVFP, 0x07 },
+ { 0x21, 0x02 }, { 0x22, 0x91 },
+ { 0x29, 0x07 }, { 0x33, 0x0b },
+ { 0x35, 0x0b }, { 0x37, 0x1d },
+ { 0x38, 0x71 }, { 0x39, 0x2a },
+ { OV7670_REG_COM12, 0x78 }, { 0x4d, 0x40 },
+ { 0x4e, 0x20 }, { OV7670_REG_GFIX, 0 },
+ { 0x6b, 0x4a }, { 0x74, 0x10 },
+ { 0x8d, 0x4f }, { 0x8e, 0 },
+ { 0x8f, 0 }, { 0x90, 0 },
+ { 0x91, 0 }, { 0x96, 0 },
+ { 0x9a, 0 }, { 0xb0, 0x84 },
+ { 0xb1, 0x0c }, { 0xb2, 0x0e },
+ { 0xb3, 0x82 }, { 0xb8, 0x0a },
+
+ /* More reserved magic, some of which tweaks white balance */
+ { 0x43, 0x0a }, { 0x44, 0xf0 },
+ { 0x45, 0x34 }, { 0x46, 0x58 },
+ { 0x47, 0x28 }, { 0x48, 0x3a },
+ { 0x59, 0x88 }, { 0x5a, 0x88 },
+ { 0x5b, 0x44 }, { 0x5c, 0x67 },
+ { 0x5d, 0x49 }, { 0x5e, 0x0e },
+ { 0x6c, 0x0a }, { 0x6d, 0x55 },
+ { 0x6e, 0x11 }, { 0x6f, 0x9f },
+ /* "9e for advance AWB" */
+ { 0x6a, 0x40 }, { OV7670_REG_BLUE, 0x40 },
+ { OV7670_REG_RED, 0x60 },
+ { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ | OV7670_COM8_AECSTEP
+ | OV7670_COM8_BFILT
+ | OV7670_COM8_AGC
+ | OV7670_COM8_AEC
+ | OV7670_COM8_AWB },
+
+ /* Matrix coefficients */
+ { 0x4f, 0x80 }, { 0x50, 0x80 },
+ { 0x51, 0 }, { 0x52, 0x22 },
+ { 0x53, 0x5e }, { 0x54, 0x80 },
+ { 0x58, 0x9e },
+
+ { OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
+ { OV7670_REG_EDGE, 0 },
+ { 0x75, 0x05 }, { 0x76, 0xe1 },
+ { 0x4c, 0 }, { 0x77, 0x01 },
+ { OV7670_REG_COM13, 0xc3 }, { 0x4b, 0x09 },
+ { 0xc9, 0x60 }, { OV7670_REG_COM16, 0x38 },
+ { 0x56, 0x40 },
+
+ { 0x34, 0x11 },
+ { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
+ { 0xa4, 0x88 }, { 0x96, 0 },
+ { 0x97, 0x30 }, { 0x98, 0x20 },
+ { 0x99, 0x30 }, { 0x9a, 0x84 },
+ { 0x9b, 0x29 }, { 0x9c, 0x03 },
+ { 0x9d, 0x4c }, { 0x9e, 0x3f },
+ { 0x78, 0x04 },
+
+ /* Extra-weird stuff. Some sort of multiplexor register */
+ { 0x79, 0x01 }, { 0xc8, 0xf0 },
+ { 0x79, 0x0f }, { 0xc8, 0x00 },
+ { 0x79, 0x10 }, { 0xc8, 0x7e },
+ { 0x79, 0x0a }, { 0xc8, 0x80 },
+ { 0x79, 0x0b }, { 0xc8, 0x01 },
+ { 0x79, 0x0c }, { 0xc8, 0x0f },
+ { 0x79, 0x0d }, { 0xc8, 0x20 },
+ { 0x79, 0x09 }, { 0xc8, 0x80 },
+ { 0x79, 0x02 }, { 0xc8, 0xc0 },
+ { 0x79, 0x03 }, { 0xc8, 0x40 },
+ { 0x79, 0x05 }, { 0xc8, 0x30 },
+ { 0x79, 0x26 },
+
+ /* Format YUV422 */
+ { OV7670_REG_COM7, OV7670_COM7_YUV }, /* Selects YUV mode */
+ { OV7670_REG_RGB444, 0 }, /* No RGB444 please */
+ { OV7670_REG_COM1, 0 },
+ { OV7670_REG_COM15, OV7670_COM15_R00FF },
+ { OV7670_REG_COM9, 0x18 },
+ /* 4x gain ceiling; 0x8 is reserved bit */
+ { 0x4f, 0x80 }, /* "matrix coefficient 1" */
+ { 0x50, 0x80 }, /* "matrix coefficient 2" */
+ { 0x52, 0x22 }, /* "matrix coefficient 4" */
+ { 0x53, 0x5e }, /* "matrix coefficient 5" */
+ { 0x54, 0x80 }, /* "matrix coefficient 6" */
+ { OV7670_REG_COM13, OV7670_COM13_GAMMA|OV7670_COM13_UVSAT },
+};
+
+ PDEBUG(D_PROBE, "starting OV7xx0 configuration");
+
+/* jfm:already done? */
+ if (init_ov_sensor(sd) < 0)
+ PDEBUG(D_ERR, "Failed to read sensor ID");
+ else
+ PDEBUG(D_PROBE, "OV7xx0 initialized");
+
+ /* Detect sensor (sub)type */
+ rc = i2c_r(sd, OV7610_REG_COM_I);
+
+ /* add OV7670 here
+ * it appears to be wrongly detected as a 7610 by default */
+ if (rc < 0) {
+ PDEBUG(D_ERR, "Error detecting sensor type");
+ return -1;
+ }
+ if ((rc & 3) == 3) {
+ /* quick hack to make OV7670s work */
+ high = i2c_r(sd, 0x0a);
+ low = i2c_r(sd, 0x0b);
+ /* info("%x, %x", high, low); */
+ if (high == 0x76 && low == 0x73) {
+ PDEBUG(D_PROBE, "Sensor is an OV7670");
+ sd->sensor = SEN_OV7670;
+ } else {
+ PDEBUG(D_PROBE, "Sensor is an OV7610");
+ sd->sensor = SEN_OV7610;
+ }
+ } else if ((rc & 3) == 1) {
+ /* I don't know what's different about the 76BE yet. */
+ if (i2c_r(sd, 0x15) & 1)
+ PDEBUG(D_PROBE, "Sensor is an OV7620AE");
+ else
+ PDEBUG(D_PROBE, "Sensor is an OV76BE");
+
+ /* OV511+ will return all zero isoc data unless we
+ * configure the sensor as a 7620. Someone needs to
+ * find the exact reg. setting that causes this. */
+ sd->sensor = SEN_OV76BE;
+ } else if ((rc & 3) == 0) {
+ /* try to read product id registers */
+ high = i2c_r(sd, 0x0a);
+ if (high < 0) {
+ PDEBUG(D_ERR, "Error detecting camera chip PID");
+ return high;
+ }
+ low = i2c_r(sd, 0x0b);
+ if (low < 0) {
+ PDEBUG(D_ERR, "Error detecting camera chip VER");
+ return low;
+ }
+ if (high == 0x76) {
+ if (low == 0x30) {
+ PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");
+ sd->sensor = SEN_OV7630;
+ } else if (low == 0x40) {
+ PDEBUG(D_PROBE, "Sensor is an OV7645");
+ sd->sensor = SEN_OV7640; /* FIXME */
+ } else if (low == 0x45) {
+ PDEBUG(D_PROBE, "Sensor is an OV7645B");
+ sd->sensor = SEN_OV7640; /* FIXME */
+ } else if (low == 0x48) {
+ PDEBUG(D_PROBE, "Sensor is an OV7648");
+ sd->sensor = SEN_OV7640; /* FIXME */
+ } else {
+ PDEBUG(D_PROBE, "Unknown sensor: 0x76%X", low);
+ return -1;
+ }
+ } else {
+ PDEBUG(D_PROBE, "Sensor is an OV7620");
+ sd->sensor = SEN_OV7620;
+ }
+ } else {
+ PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
+ return -1;
+ }
+
+ if (sd->sensor == SEN_OV7620) {
+ PDEBUG(D_PROBE, "Writing 7620 registers");
+ if (write_i2c_regvals(sd, norm_7620,
+ sizeof norm_7620 / sizeof norm_7620[0]))
+ return -1;
+ } else if (sd->sensor == SEN_OV7630) {
+ PDEBUG(D_ERR, "7630 is not supported by this driver version");
+ return -1;
+ } else if (sd->sensor == SEN_OV7640) {
+ PDEBUG(D_PROBE, "Writing 7640 registers");
+ if (write_i2c_regvals(sd, norm_7640,
+ sizeof norm_7640 / sizeof norm_7640[0]))
+ return -1;
+ } else if (sd->sensor == SEN_OV7670) {
+ PDEBUG(D_PROBE, "Writing 7670 registers");
+ if (write_i2c_regvals(sd, norm_7670,
+ sizeof norm_7670 / sizeof norm_7670[0]))
+ return -1;
+ } else {
+ PDEBUG(D_PROBE, "Writing 7610 registers");
+ if (write_i2c_regvals(sd, norm_7610,
+ sizeof norm_7610 / sizeof norm_7610[0]))
+ return -1;
+ }
+
+ /* Set sensor-specific vars */
+ sd->maxwidth = 640;
+ sd->maxheight = 480;
+ return 0;
+}
+
+/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
+static int ov6xx0_configure(struct sd *sd)
+{
+ int rc;
+ static const struct ov_i2c_regvals norm_6x20[] = {
+ { 0x12, 0x80 }, /* reset */
+ { 0x11, 0x01 },
+ { 0x03, 0x60 },
+ { 0x05, 0x7f }, /* For when autoadjust is off */
+ { 0x07, 0xa8 },
+ /* The ratio of 0x0c and 0x0d controls the white point */
+ { 0x0c, 0x24 },
+ { 0x0d, 0x24 },
+ { 0x0f, 0x15 }, /* COMS */
+ { 0x10, 0x75 }, /* AEC Exposure time */
+ { 0x12, 0x24 }, /* Enable AGC */
+ { 0x14, 0x04 },
+ /* 0x16: 0x06 helps frame stability with moving objects */
+ { 0x16, 0x06 },
+/* { 0x20, 0x30 }, * Aperture correction enable */
+ { 0x26, 0xb2 }, /* BLC enable */
+ /* 0x28: 0x05 Selects RGB format if RGB on */
+ { 0x28, 0x05 },
+ { 0x2a, 0x04 }, /* Disable framerate adjust */
+/* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */
+ { 0x2d, 0x99 },
+ { 0x33, 0xa0 }, /* Color Processing Parameter */
+ { 0x34, 0xd2 }, /* Max A/D range */
+ { 0x38, 0x8b },
+ { 0x39, 0x40 },
+
+ { 0x3c, 0x39 }, /* Enable AEC mode changing */
+ { 0x3c, 0x3c }, /* Change AEC mode */
+ { 0x3c, 0x24 }, /* Disable AEC mode changing */
+
+ { 0x3d, 0x80 },
+ /* These next two registers (0x4a, 0x4b) are undocumented.
+ * They control the color balance */
+ { 0x4a, 0x80 },
+ { 0x4b, 0x80 },
+ { 0x4d, 0xd2 }, /* This reduces noise a bit */
+ { 0x4e, 0xc1 },
+ { 0x4f, 0x04 },
+/* Do 50-53 have any effect? */
+/* Toggle 0x12[2] off and on here? */
+ };
+
+ static const struct ov_i2c_regvals norm_6x30[] = {
+ { 0x12, 0x80 }, /* Reset */
+ { 0x00, 0x1f }, /* Gain */
+ { 0x01, 0x99 }, /* Blue gain */
+ { 0x02, 0x7c }, /* Red gain */
+ { 0x03, 0xc0 }, /* Saturation */
+ { 0x05, 0x0a }, /* Contrast */
+ { 0x06, 0x95 }, /* Brightness */
+ { 0x07, 0x2d }, /* Sharpness */
+ { 0x0c, 0x20 },
+ { 0x0d, 0x20 },
+ { 0x0e, 0x20 },
+ { 0x0f, 0x05 },
+ { 0x10, 0x9a },
+ { 0x11, 0x00 }, /* Pixel clock = fastest */
+ { 0x12, 0x24 }, /* Enable AGC and AWB */
+ { 0x13, 0x21 },
+ { 0x14, 0x80 },
+ { 0x15, 0x01 },
+ { 0x16, 0x03 },
+ { 0x17, 0x38 },
+ { 0x18, 0xea },
+ { 0x19, 0x04 },
+ { 0x1a, 0x93 },
+ { 0x1b, 0x00 },
+ { 0x1e, 0xc4 },
+ { 0x1f, 0x04 },
+ { 0x20, 0x20 },
+ { 0x21, 0x10 },
+ { 0x22, 0x88 },
+ { 0x23, 0xc0 }, /* Crystal circuit power level */
+ { 0x25, 0x9a }, /* Increase AEC black ratio */
+ { 0x26, 0xb2 }, /* BLC enable */
+ { 0x27, 0xa2 },
+ { 0x28, 0x00 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x84 }, /* 60 Hz power */
+ { 0x2b, 0xa8 }, /* 60 Hz power */
+ { 0x2c, 0xa0 },
+ { 0x2d, 0x95 }, /* Enable auto-brightness */
+ { 0x2e, 0x88 },
+ { 0x33, 0x26 },
+ { 0x34, 0x03 },
+ { 0x36, 0x8f },
+ { 0x37, 0x80 },
+ { 0x38, 0x83 },
+ { 0x39, 0x80 },
+ { 0x3a, 0x0f },
+ { 0x3b, 0x3c },
+ { 0x3c, 0x1a },
+ { 0x3d, 0x80 },
+ { 0x3e, 0x80 },
+ { 0x3f, 0x0e },
+ { 0x40, 0x00 }, /* White bal */
+ { 0x41, 0x00 }, /* White bal */
+ { 0x42, 0x80 },
+ { 0x43, 0x3f }, /* White bal */
+ { 0x44, 0x80 },
+ { 0x45, 0x20 },
+ { 0x46, 0x20 },
+ { 0x47, 0x80 },
+ { 0x48, 0x7f },
+ { 0x49, 0x00 },
+ { 0x4a, 0x00 },
+ { 0x4b, 0x80 },
+ { 0x4c, 0xd0 },
+ { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
+ { 0x4e, 0x40 },
+ { 0x4f, 0x07 }, /* UV avg., col. killer: max */
+ { 0x50, 0xff },
+ { 0x54, 0x23 }, /* Max AGC gain: 18dB */
+ { 0x55, 0xff },
+ { 0x56, 0x12 },
+ { 0x57, 0x81 },
+ { 0x58, 0x75 },
+ { 0x59, 0x01 }, /* AGC dark current comp.: +1 */
+ { 0x5a, 0x2c },
+ { 0x5b, 0x0f }, /* AWB chrominance levels */
+ { 0x5c, 0x10 },
+ { 0x3d, 0x80 },
+ { 0x27, 0xa6 },
+ { 0x12, 0x20 }, /* Toggle AWB */
+ { 0x12, 0x24 },
+ };
+
+ PDEBUG(D_PROBE, "starting sensor configuration");
+
+ if (init_ov_sensor(sd) < 0) {
+ PDEBUG(D_ERR, "Failed to read sensor ID.");
+ return -1;
+ }
+ PDEBUG(D_PROBE, "OV6xx0 sensor detected");
+
+ /* Detect sensor (sub)type */
+ rc = i2c_r(sd, OV7610_REG_COM_I);
+ if (rc < 0) {
+ PDEBUG(D_ERR, "Error detecting sensor type");
+ return -1;
+ }
+
+ /* Ugh. The first two bits are the version bits, but
+ * the entire register value must be used. I guess OVT
+ * underestimated how many variants they would make. */
+ if (rc == 0x00) {
+ sd->sensor = SEN_OV6630;
+ PDEBUG(D_ERR,
+ "WARNING: Sensor is an OV66308. Your camera may have");
+ PDEBUG(D_ERR, "been misdetected in previous driver versions.");
+ } else if (rc == 0x01) {
+ sd->sensor = SEN_OV6620;
+ PDEBUG(D_PROBE, "Sensor is an OV6620");
+ } else if (rc == 0x02) {
+ sd->sensor = SEN_OV6630;
+ PDEBUG(D_PROBE, "Sensor is an OV66308AE");
+ } else if (rc == 0x03) {
+ sd->sensor = SEN_OV6630;
+ PDEBUG(D_PROBE, "Sensor is an OV66308AF");
+ } else if (rc == 0x90) {
+ sd->sensor = SEN_OV6630;
+ PDEBUG(D_ERR,
+ "WARNING: Sensor is an OV66307. Your camera may have");
+ PDEBUG(D_ERR, "been misdetected in previous driver versions.");
+ } else {
+ PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc);
+ return -1;
+ }
+
+ /* Set sensor-specific vars */
+ sd->maxwidth = 352;
+ sd->maxheight = 288;
+
+ if (sd->sensor == SEN_OV6620) {
+ PDEBUG(D_PROBE, "Writing 6x20 registers");
+ if (write_i2c_regvals(sd, norm_6x20,
+ sizeof norm_6x20 / sizeof norm_6x20[0]))
+ return -1;
+ } else {
+ PDEBUG(D_PROBE, "Writing 6x30 registers");
+ if (write_i2c_regvals(sd, norm_6x30,
+ sizeof norm_6x30 / sizeof norm_6x30[0]))
+ return -1;
+ }
+ return 0;
+}
+
+/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
+static void ov51x_led_control(struct sd *sd, int on)
+{
+ PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off");
+
+/* if (sd->bridge == BRG_OV511PLUS) */
+/* reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0); */
+/* else if (sd->bridge == BRG_OV519) */
+ reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */
+/* else if (sd->bclass == BCL_OV518) */
+/* reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02); */
+}
+
+/* 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;
+
+/* (from ov519_configure) */
+ static const struct ov_regvals init_519[] = {
+ { 0x5a, 0x6d }, /* EnableSystem */
+/* jfm trace usbsnoop3-1.txt */
+/* jfm 53 = fb */
+ { 0x53, 0x9b },
+ { 0x54, 0xff }, /* set bit2 to enable jpeg */
+ { 0x5d, 0x03 },
+ { 0x49, 0x01 },
+ { 0x48, 0x00 },
+ /* Set LED pin to output mode. Bit 4 must be cleared or sensor
+ * detection will fail. This deserves further investigation. */
+ { OV519_GPIO_IO_CTRL0, 0xee },
+ { 0x51, 0x0f }, /* SetUsbInit */
+ { 0x51, 0x00 },
+ { 0x22, 0x00 },
+ /* windows reads 0x55 at this point*/
+ };
+
+ if (write_regvals(sd, init_519, ARRAY_SIZE(init_519)))
+ goto error;
+/* jfm: not seen in windows trace */
+ if (ov519_init_compression(sd))
+ goto error;
+ ov51x_led_control(sd, 0); /* turn LED off */
+
+ /* Test for 76xx */
+ sd->primary_i2c_slave = OV7xx0_SID;
+ if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0)
+ goto error;
+
+ /* The OV519 must be more aggressive about sensor detection since
+ * I2C write will never fail if the sensor is not present. We have
+ * to try to initialize the sensor to detect its presence */
+ if (init_ov_sensor(sd) < 0) {
+ /* Test for 6xx0 */
+ sd->primary_i2c_slave = OV6xx0_SID;
+ if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0)
+ goto error;
+
+ if (init_ov_sensor(sd) < 0) {
+ /* Test for 8xx0 */
+ sd->primary_i2c_slave = OV8xx0_SID;
+ if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0)
+ goto error;
+
+ if (init_ov_sensor(sd) < 0) {
+ PDEBUG(D_ERR,
+ "Can't determine sensor slave IDs");
+ goto error;
+ } else {
+ if (ov8xx0_configure(sd) < 0) {
+ PDEBUG(D_ERR,
+ "Failed to configure OV8xx0 sensor");
+ goto error;
+ }
+ }
+ } else {
+ if (ov6xx0_configure(sd) < 0) {
+ PDEBUG(D_ERR, "Failed to configure OV6xx0");
+ goto error;
+ }
+ }
+ } else {
+ if (ov7xx0_configure(sd) < 0) {
+ PDEBUG(D_ERR, "Failed to configure OV7xx0");
+ goto error;
+ }
+ }
+
+ cam = &gspca_dev->cam;
+ cam->epaddr = OV511_ENDPOINT_ADDRESS;
+ if (sd->maxwidth == 640) {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ } else {
+ cam->cam_mode = sif_mode;
+ cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ }
+ cam->dev_name = (char *) id->driver_info;
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+ return 0;
+error:
+ PDEBUG(D_ERR, "OV519 Config failed");
+ return -EBUSY;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+/* Sets up the OV519 with the given image parameters
+ *
+ * OV519 needs a completely different approach, until we can figure out what
+ * the individual registers do.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int ov519_mode_init_regs(struct sd *sd,
+ int width, int height)
+{
+ static const struct ov_regvals mode_init_519_ov7670[] = {
+ { 0x5d, 0x03 }, /* Turn off suspend mode */
+ { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */
+ { 0x54, 0x0f }, /* bit2 (jpeg enable) */
+ { 0xa2, 0x20 }, /* a2-a5 are undocumented */
+ { 0xa3, 0x18 },
+ { 0xa4, 0x04 },
+ { 0xa5, 0x28 },
+ { 0x37, 0x00 }, /* SetUsbInit */
+ { 0x55, 0x02 }, /* 4.096 Mhz audio clock */
+ /* Enable both fields, YUV Input, disable defect comp (why?) */
+ { 0x20, 0x0c },
+ { 0x21, 0x38 },
+ { 0x22, 0x1d },
+ { 0x17, 0x50 }, /* undocumented */
+ { 0x37, 0x00 }, /* undocumented */
+ { 0x40, 0xff }, /* I2C timeout counter */
+ { 0x46, 0x00 }, /* I2C clock prescaler */
+ { 0x59, 0x04 }, /* new from windrv 090403 */
+ { 0xff, 0x00 }, /* undocumented */
+ /* windows reads 0x55 at this point, why? */
+ };
+
+ static const struct ov_regvals mode_init_519[] = {
+ { 0x5d, 0x03 }, /* Turn off suspend mode */
+ { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */
+ { 0x54, 0x0f }, /* bit2 (jpeg enable) */
+ { 0xa2, 0x20 }, /* a2-a5 are undocumented */
+ { 0xa3, 0x18 },
+ { 0xa4, 0x04 },
+ { 0xa5, 0x28 },
+ { 0x37, 0x00 }, /* SetUsbInit */
+ { 0x55, 0x02 }, /* 4.096 Mhz audio clock */
+ /* Enable both fields, YUV Input, disable defect comp (why?) */
+ { 0x22, 0x1d },
+ { 0x17, 0x50 }, /* undocumented */
+ { 0x37, 0x00 }, /* undocumented */
+ { 0x40, 0xff }, /* I2C timeout counter */
+ { 0x46, 0x00 }, /* I2C clock prescaler */
+ { 0x59, 0x04 }, /* new from windrv 090403 */
+ { 0xff, 0x00 }, /* undocumented */
+ /* windows reads 0x55 at this point, why? */
+ };
+
+/* int hi_res; */
+
+ PDEBUG(D_CONF, "mode init %dx%d", width, height);
+
+/* if (width >= 800 && height >= 600)
+ hi_res = 1;
+ else
+ hi_res = 0; */
+
+/* if (ov51x_stop(sd) < 0)
+ return -EIO; */
+
+ /******** Set the mode ********/
+ if (sd->sensor != SEN_OV7670) {
+ if (write_regvals(sd, mode_init_519,
+ ARRAY_SIZE(mode_init_519)))
+ return -EIO;
+ } else {
+ if (write_regvals(sd, mode_init_519_ov7670,
+ ARRAY_SIZE(mode_init_519_ov7670)))
+ return -EIO;
+ }
+
+ if (sd->sensor == SEN_OV7640) {
+ /* Select 8-bit input mode */
+ reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10);
+ }
+
+ reg_w(sd, OV519_CAM_H_SIZE, width >> 4);
+ reg_w(sd, OV519_CAM_V_SIZE, height >> 3);
+ reg_w(sd, OV519_CAM_X_OFFSETL, 0x00);
+ reg_w(sd, OV519_CAM_X_OFFSETH, 0x00);
+ reg_w(sd, OV519_CAM_Y_OFFSETL, 0x00);
+ reg_w(sd, OV519_CAM_Y_OFFSETH, 0x00);
+ reg_w(sd, OV519_CAM_DIVIDER, 0x00);
+ reg_w(sd, OV519_CAM_FORMAT, 0x03); /* YUV422 */
+ reg_w(sd, 0x26, 0x00); /* Undocumented */
+
+ /******** Set the framerate ********/
+ if (frame_rate > 0)
+ sd->frame_rate = frame_rate;
+
+/* FIXME: These are only valid at the max resolution. */
+ sd->clockdiv = 0;
+ if (sd->sensor == SEN_OV7640) {
+ switch (sd->frame_rate) {
+/*jfm: default was 30 fps */
+ case 30:
+ reg_w(sd, 0xa4, 0x0c);
+ reg_w(sd, 0x23, 0xff);
+ break;
+ case 25:
+ reg_w(sd, 0xa4, 0x0c);
+ reg_w(sd, 0x23, 0x1f);
+ break;
+ case 20:
+ reg_w(sd, 0xa4, 0x0c);
+ reg_w(sd, 0x23, 0x1b);
+ break;
+ default:
+/* case 15: */
+ reg_w(sd, 0xa4, 0x04);
+ reg_w(sd, 0x23, 0xff);
+ sd->clockdiv = 1;
+ break;
+ case 10:
+ reg_w(sd, 0xa4, 0x04);
+ reg_w(sd, 0x23, 0x1f);
+ sd->clockdiv = 1;
+ break;
+ case 5:
+ reg_w(sd, 0xa4, 0x04);
+ reg_w(sd, 0x23, 0x1b);
+ sd->clockdiv = 1;
+ break;
+ }
+ } else if (sd->sensor == SEN_OV8610) {
+ switch (sd->frame_rate) {
+ default: /* 15 fps */
+/* case 15: */
+ reg_w(sd, 0xa4, 0x06);
+ reg_w(sd, 0x23, 0xff);
+ break;
+ case 10:
+ reg_w(sd, 0xa4, 0x06);
+ reg_w(sd, 0x23, 0x1f);
+ break;
+ case 5:
+ reg_w(sd, 0xa4, 0x06);
+ reg_w(sd, 0x23, 0x1b);
+ break;
+ }
+ sd->clockdiv = 0;
+ } else if (sd->sensor == SEN_OV7670) { /* guesses, based on 7640 */
+ PDEBUG(D_STREAM, "Setting framerate to %d fps",
+ (sd->frame_rate == 0) ? 15 : sd->frame_rate);
+ switch (sd->frame_rate) {
+ case 30:
+ reg_w(sd, 0xa4, 0x10);
+ reg_w(sd, 0x23, 0xff);
+ break;
+ case 20:
+ reg_w(sd, 0xa4, 0x10);
+ reg_w(sd, 0x23, 0x1b);
+ break;
+ default: /* 15 fps */
+/* case 15: */
+ reg_w(sd, 0xa4, 0x10);
+ reg_w(sd, 0x23, 0xff);
+ sd->clockdiv = 1;
+ break;
+ }
+ }
+
+/* if (ov51x_restart(sd) < 0)
+ return -EIO; */
+
+ /* Reset it just for good measure */
+/* if (ov51x_reset(sd, OV511_RESET_NOREGS) < 0)
+ return -EIO; */
+ return 0;
+}
+
+static int mode_init_ov_sensor_regs(struct sd *sd,
+ struct ovsensor_window *win)
+{
+ int qvga = win->quarter;
+
+ /******** Mode (VGA/QVGA) and sensor specific regs ********/
+ switch (sd->sensor) {
+ case SEN_OV8610:
+ /* For OV8610 qvga means qsvga */
+ i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5);
+ break;
+ case SEN_OV7610:
+ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+ break;
+ case SEN_OV7620:
+/* i2c_w(sd, 0x2b, 0x00); */
+ 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);
+ break;
+ case SEN_OV76BE:
+/* i2c_w(sd, 0x2b, 0x00); */
+ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+ break;
+ case SEN_OV7640:
+/* i2c_w(sd, 0x2b, 0x00); */
+ 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); */
+ break;
+ case SEN_OV7670:
+ /* set COM7_FMT_VGA or COM7_FMT_QVGA
+ * do we need to set anything else?
+ * HSTART etc are set in set_ov_sensor_window itself */
+ i2c_w_mask(sd, OV7670_REG_COM7,
+ qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA,
+ OV7670_COM7_FMT_MASK);
+ break;
+ case SEN_OV6620:
+ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+ break;
+ case SEN_OV6630:
+ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /******** Palette-specific regs ********/
+/* Need to do work here for the OV7670 */
+
+ if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
+ /* not valid on the OV6620/OV7620/6630? */
+ i2c_w_mask(sd, 0x0e, 0x00, 0x40);
+ }
+
+ /* 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_OV7640)
+ i2c_w_mask(sd, 0x13, 0x00, 0x20);
+/* } */
+
+ /******** Clock programming ********/
+ /* The OV6620 needs special handling. This prevents the
+ * severe banding that normally occurs */
+ if (sd->sensor == SEN_OV6620) {
+
+ /* Clock down */
+ i2c_w(sd, 0x2a, 0x04);
+ i2c_w(sd, 0x11, win->clockdiv);
+ i2c_w(sd, 0x2a, 0x84);
+ /* This next setting is critical. It seems to improve
+ * the gain or the contrast. The "reserved" bits seem
+ * to have some effect in this case. */
+ i2c_w(sd, 0x2d, 0x85);
+ } else if (win->clockdiv >= 0) {
+ i2c_w(sd, 0x11, win->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 (win->width == 640 /*&& win->height == 480*/)
+ i2c_w(sd, 0x35, 0x9e);
+ else
+ i2c_w(sd, 0x35, 0x1e);
+ }
+ return 0;
+}
+
+static int set_ov_sensor_window(struct sd *sd,
+ struct ovsensor_window *win)
+{
+ int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
+ int ret, hstart, hstop, vstop, vstart;
+ __u8 v;
+
+ /* The different sensor ICs handle setting up of window differently.
+ * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */
+ switch (sd->sensor) {
+ case SEN_OV8610:
+ hwsbase = 0x1e;
+ hwebase = 0x1e;
+ vwsbase = 0x02;
+ vwebase = 0x02;
+ break;
+ case SEN_OV7610:
+ case SEN_OV76BE:
+ hwsbase = 0x38;
+ hwebase = 0x3a;
+ vwsbase = vwebase = 0x05;
+ break;
+ case SEN_OV6620:
+ case SEN_OV6630:
+ hwsbase = 0x38;
+ hwebase = 0x3a;
+ vwsbase = 0x05;
+ vwebase = 0x06;
+ break;
+ case SEN_OV7620:
+ hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */
+ hwebase = 0x2f;
+ vwsbase = vwebase = 0x05;
+ break;
+ case SEN_OV7640:
+ 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;
+ }
+
+ switch (sd->sensor) {
+ case SEN_OV6620:
+ case SEN_OV6630:
+ if (win->quarter) { /* QCIF */
+ hwscale = 0;
+ vwscale = 0;
+ } else { /* CIF */
+ hwscale = 1;
+ vwscale = 1; /* The datasheet says 0;
+ * it's wrong */
+ }
+ break;
+ case SEN_OV8610:
+ if (win->quarter) { /* QSVGA */
+ hwscale = 1;
+ vwscale = 1;
+ } else { /* SVGA */
+ hwscale = 2;
+ vwscale = 2;
+ }
+ break;
+ default: /* SEN_OV7xx0 */
+ if (win->quarter) { /* QVGA */
+ hwscale = 1;
+ vwscale = 0;
+ } else { /* VGA */
+ hwscale = 2;
+ vwscale = 1;
+ }
+ }
+
+ ret = mode_init_ov_sensor_regs(sd, win);
+ 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 */
+
+ /* 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 (win->quarter) { /* QVGA from ov7670.c by
+ * Jonathan Corbet */
+ hstart = 164;
+ hstop = 20;
+ 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) & 0xff);
+ i2c_w(sd, OV7670_REG_HSTOP, (hstop >> 3) & 0xff);
+ 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) & 0xff);
+ i2c_w(sd, OV7670_REG_VSTOP, (vstop >> 2) & 0xff);
+ 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 + (win->x >> hwscale));
+ i2c_w(sd, 0x18, hwebase + ((win->x + win->width) >> hwscale));
+ i2c_w(sd, 0x19, vwsbase + (win->y >> vwscale));
+ i2c_w(sd, 0x1a, vwebase + ((win->y + win->height) >> vwscale));
+ }
+ return 0;
+}
+
+static int ov_sensor_mode_setup(struct sd *sd,
+ int width, int height)
+{
+ struct ovsensor_window win;
+
+/* win.format = mode; */
+
+ /* Unless subcapture is enabled,
+ * center the image window and downsample
+ * if possible to increase the field of view */
+ /* NOTE: OV518(+) and OV519 does downsampling on its own */
+ win.width = width;
+ win.height = height;
+ if (width == sd->maxwidth)
+ win.quarter = 0;
+ else
+ win.quarter = 1;
+
+ /* Center it */
+ win.x = (win.width - width) / 2;
+ win.y = (win.height - height) / 2;
+
+ /* Clock is determined by OV519 frame rate code */
+ win.clockdiv = sd->clockdiv;
+
+ PDEBUG(D_CONF, "Setting clock divider to %d", win.clockdiv);
+ return set_ov_sensor_window(sd, &win);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+
+ ret = ov519_mode_init_regs(sd, gspca_dev->width, gspca_dev->height);
+ if (ret < 0)
+ goto out;
+ ret = ov_sensor_mode_setup(sd, gspca_dev->width, gspca_dev->height);
+ if (ret < 0)
+ goto out;
+
+ ret = ov51x_restart((struct sd *) gspca_dev);
+ if (ret < 0)
+ goto out;
+ PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
+ ov51x_led_control(sd, 1);
+ return;
+out:
+ PDEBUG(D_ERR, "camera start error:%d", ret);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ ov51x_stop((struct sd *) gspca_dev);
+ ov51x_led_control((struct sd *) gspca_dev, 0);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ /* Header of ov519 is 16 bytes:
+ * Byte Value Description
+ * 0 0xff magic
+ * 1 0xff magic
+ * 2 0xff magic
+ * 3 0xXX 0x50 = SOF, 0x51 = EOF
+ * 9 0xXX 0x01 initial frame without data,
+ * 0x00 standard frame with image
+ * 14 Lo in EOF: length of image data / 8
+ * 15 Hi
+ */
+
+ if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) {
+ switch (data[3]) {
+ case 0x50: /* start of frame */
+#define HDRSZ 16
+ data += HDRSZ;
+ len -= HDRSZ;
+#undef HDRSZ
+ if (data[0] == 0xff || data[1] == 0xd8)
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, len);
+ else
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ case 0x51: /* end of frame */
+ if (data[9] != 0)
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+ return;
+ }
+ }
+
+ /* intermediate packet */
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data, len);
+}
+
+/* -- management routines -- */
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int val;
+/* int was_streaming; */
+
+ val = sd->brightness;
+ PDEBUG(D_CONF, "brightness:%d", val);
+/* was_streaming = gspca_dev->streaming;
+ * if (was_streaming)
+ * ov51x_stop(sd); */
+ switch (sd->sensor) {
+ case SEN_OV8610:
+ case SEN_OV7610:
+ case SEN_OV76BE:
+ case SEN_OV6620:
+ case SEN_OV6630:
+ case SEN_OV7640:
+ i2c_w(sd, OV7610_REG_BRT, val);
+ break;
+ case SEN_OV7620:
+ /* 7620 doesn't like manual changes when in auto mode */
+/*fixme
+ * if (!sd->auto_brt) */
+ i2c_w(sd, OV7610_REG_BRT, val);
+ break;
+ case SEN_OV7670:
+/*jfm - from windblows
+ * i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_AEC); */
+ i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val));
+ break;
+ }
+/* if (was_streaming)
+ * ov51x_restart(sd); */
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int val;
+/* int was_streaming; */
+
+ val = sd->contrast;
+ PDEBUG(D_CONF, "contrast:%d", val);
+/* was_streaming = gspca_dev->streaming;
+ if (was_streaming)
+ ov51x_stop(sd); */
+ switch (sd->sensor) {
+ case SEN_OV7610:
+ case SEN_OV6620:
+ i2c_w(sd, OV7610_REG_CNT, val);
+ break;
+ case SEN_OV6630:
+ i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f);
+ case SEN_OV8610: {
+ static const __u8 ctab[] = {
+ 0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f
+ };
+
+ /* Use Y gamma control instead. Bit 0 enables it. */
+ i2c_w(sd, 0x64, ctab[val >> 5]);
+ break;
+ }
+ case SEN_OV7620: {
+ static const __u8 ctab[] = {
+ 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
+ 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
+ };
+
+ /* Use Y gamma control instead. Bit 0 enables it. */
+ 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);
+ break;
+ }
+/* if (was_streaming)
+ ov51x_restart(sd); */
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int val;
+/* int was_streaming; */
+
+ val = sd->colors;
+ PDEBUG(D_CONF, "saturation:%d", val);
+/* was_streaming = gspca_dev->streaming;
+ if (was_streaming)
+ ov51x_stop(sd); */
+ switch (sd->sensor) {
+ case SEN_OV8610:
+ case SEN_OV7610:
+ case SEN_OV76BE:
+ case SEN_OV6620:
+ case SEN_OV6630:
+ i2c_w(sd, OV7610_REG_SAT, val);
+ break;
+ case SEN_OV7620:
+ /* Use UV gamma control instead. Bits 0 & 7 are reserved. */
+/* rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e);
+ if (rc < 0)
+ goto out; */
+ i2c_w(sd, OV7610_REG_SAT, val);
+ break;
+ case SEN_OV7640:
+ i2c_w(sd, OV7610_REG_SAT, val & 0xf0);
+ break;
+ case SEN_OV7670:
+ /* supported later once I work out how to do it
+ * transparently fail now! */
+ /* set REG_COM13 values for UV sat auto mode */
+ break;
+ }
+/* if (was_streaming)
+ ov51x_restart(sd); */
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->colors;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x4052), DVNM("Creative Live! VISTA IM")},
+ {USB_DEVICE(0x041e, 0x405f), DVNM("Creative Live! VISTA VF0330")},
+ {USB_DEVICE(0x041e, 0x4060), DVNM("Creative Live! VISTA VF0350")},
+ {USB_DEVICE(0x041e, 0x4061), DVNM("Creative Live! VISTA VF0400")},
+ {USB_DEVICE(0x041e, 0x4064), DVNM("Creative Live! VISTA VF0420")},
+ {USB_DEVICE(0x041e, 0x4068), DVNM("Creative Live! VISTA VF0470")},
+ {USB_DEVICE(0x045e, 0x028c), DVNM("Microsoft xbox cam")},
+ {USB_DEVICE(0x054c, 0x0154), DVNM("Sonny toy4")},
+ {USB_DEVICE(0x054c, 0x0155), DVNM("Sonny toy5")},
+ {USB_DEVICE(0x05a9, 0x0519), DVNM("OmniVision")},
+ {USB_DEVICE(0x05a9, 0x0530), DVNM("OmniVision")},
+ {USB_DEVICE(0x05a9, 0x4519), DVNM("OmniVision")},
+ {USB_DEVICE(0x05a9, 0x8519), DVNM("OmniVision")},
+ {}
+};
+#undef DVNAME
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param(frame_rate, int, 0644);
+MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)");
+
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
new file mode 100644
index 00000000000..fa7abc41109
--- /dev/null
+++ b/drivers/media/video/gspca/pac207.c
@@ -0,0 +1,622 @@
+/*
+ * Pixart PAC207BCA library
+ *
+ * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "pac207"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_DESCRIPTION("Pixart PAC207");
+MODULE_LICENSE("GPL");
+
+#define PAC207_CTRL_TIMEOUT 100 /* ms */
+
+#define PAC207_BRIGHTNESS_MIN 0
+#define PAC207_BRIGHTNESS_MAX 255
+#define PAC207_BRIGHTNESS_DEFAULT 4 /* power on default: 4 */
+
+/* An exposure value of 4 also works (3 does not) but then we need to lower
+ the compression balance setting when in 352x288 mode, otherwise the usb
+ bandwidth is not enough and packets get dropped resulting in corrupt
+ frames. The problem with this is that when the compression balance gets
+ lowered below 0x80, the pac207 starts using a different compression
+ algorithm for some lines, these lines get prefixed with a 0x2dd2 prefix
+ and currently we do not know how to decompress these lines, so for now
+ we use a minimum exposure value of 5 */
+#define PAC207_EXPOSURE_MIN 5
+#define PAC207_EXPOSURE_MAX 26
+#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 ?? */
+#define PAC207_EXPOSURE_KNEE 11 /* 4 = 30 fps, 11 = 8, 15 = 6 */
+
+#define PAC207_GAIN_MIN 0
+#define PAC207_GAIN_MAX 31
+#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */
+#define PAC207_GAIN_KNEE 20
+
+#define PAC207_AUTOGAIN_DEADZONE 30
+/* We calculating the autogain at the end of the transfer of a frame, at this
+ moment a frame with the old settings is being transmitted, and a frame is
+ being captured with the old settings. So if we adjust the autogain we must
+ ignore atleast the 2 next frames for the new settings to come into effect
+ before doing any other adjustments */
+#define PAC207_AUTOGAIN_IGNORE_FRAMES 3
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ u8 mode;
+
+ u8 brightness;
+ u8 exposure;
+ u8 autogain;
+ u8 gain;
+
+ u8 sof_read;
+ u8 header_read;
+ u8 autogain_ignore_frames;
+
+ atomic_t avg_lum;
+};
+
+/* 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);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = PAC207_BRIGHTNESS_MIN,
+ .maximum = PAC207_BRIGHTNESS_MAX,
+ .step = 1,
+ .default_value = PAC207_BRIGHTNESS_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_EXPOSURE 1
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = PAC207_EXPOSURE_MIN,
+ .maximum = PAC207_EXPOSURE_MAX,
+ .step = 1,
+ .default_value = PAC207_EXPOSURE_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+#define SD_AUTOGAIN 2
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+#define SD_GAIN 3
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = PAC207_GAIN_MIN,
+ .maximum = PAC207_GAIN_MAX,
+ .step = 1,
+ .default_value = PAC207_GAIN_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = (176 + 2) * 144,
+ /* uncompressed, add 2 bytes / line for line header */
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ /* compressed, but only when needed (not compressed
+ when the framerate is low) */
+ .sizeimage = (352 + 2) * 288,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+static const __u8 pac207_sensor_init[][8] = {
+ {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
+ {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
+ {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
+ {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
+ {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
+};
+
+ /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
+static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
+
+static const unsigned char pac207_sof_marker[5] =
+ { 0xff, 0xff, 0x00, 0xff, 0x96 };
+
+static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
+ const u8 *buffer, u16 length)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int err;
+
+ memcpy(gspca_dev->usb_buf, buffer, length);
+
+ err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0x00, index,
+ gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
+ if (err < 0)
+ PDEBUG(D_ERR,
+ "Failed to write registers to index 0x%04X, error %d)",
+ index, err);
+
+ return err;
+}
+
+
+int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int err;
+
+ err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
+ if (err)
+ PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
+ " value 0x%02X, error %d)", index, value, err);
+
+ return err;
+}
+
+
+int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int res;
+
+ res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0x00, index,
+ gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
+ if (res < 0) {
+ PDEBUG(D_ERR,
+ "Failed to read a register (index 0x%04X, error %d)",
+ index, res);
+ return res;
+ }
+
+ return gspca_dev->usb_buf[0];
+}
+
+/* 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;
+ u8 idreg[2];
+
+ idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
+ idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
+ idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
+ idreg[1] = idreg[1] & 0x0f;
+ PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
+ idreg[0], idreg[1]);
+
+ if (idreg[0] != 0x27) {
+ PDEBUG(D_PROBE, "Error invalid sensor ID!");
+ return -ENODEV;
+ }
+
+ pac207_write_reg(gspca_dev, 0x41, 0x00);
+ /* Bit_0=Image Format,
+ * Bit_1=LED,
+ * Bit_2=Compression test mode enable */
+ pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
+ pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
+
+ PDEBUG(D_PROBE,
+ "Pixart PAC207BCA Image Processor and Control Chip detected"
+ " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x05;
+ cam->cam_mode = sif_mode;
+ cam->nmodes = ARRAY_SIZE(sif_mode);
+ sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
+ sd->exposure = PAC207_EXPOSURE_DEFAULT;
+ sd->gain = PAC207_GAIN_DEFAULT;
+
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = 1;
+ return 0;
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 mode;
+
+ pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
+ pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
+ pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
+ pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
+ pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
+ pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
+ pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
+
+ /* Compression Balance */
+ if (gspca_dev->width == 176)
+ pac207_write_reg(gspca_dev, 0x4a, 0xff);
+ else
+ pac207_write_reg(gspca_dev, 0x4a, 0x88);
+ pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
+ pac207_write_reg(gspca_dev, 0x08, sd->brightness);
+
+ /* PGA global gain (Bit 4-0) */
+ pac207_write_reg(gspca_dev, 0x0e, sd->gain);
+ pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
+
+ mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
+ if (gspca_dev->width == 176) { /* 176x144 */
+ mode |= 0x01;
+ PDEBUG(D_STREAM, "pac207_start mode 176x144");
+ } else { /* 352x288 */
+ PDEBUG(D_STREAM, "pac207_start mode 352x288");
+ }
+ pac207_write_reg(gspca_dev, 0x41, mode);
+
+ pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
+ pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
+ msleep(10);
+ pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
+
+ sd->sof_read = 0;
+ sd->autogain_ignore_frames = 0;
+ atomic_set(&sd->avg_lum, -1);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
+ pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
+ pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int avg_lum = atomic_read(&sd->avg_lum);
+
+ if (avg_lum == -1)
+ return;
+
+ if (sd->autogain_ignore_frames > 0)
+ sd->autogain_ignore_frames--;
+ else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
+ 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
+ PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
+ sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
+}
+
+static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
+ unsigned char *m, int len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+
+ /* Search for the SOF marker (fixed part) in the header */
+ for (i = 0; i < len; i++) {
+ if (m[i] == pac207_sof_marker[sd->sof_read]) {
+ sd->sof_read++;
+ if (sd->sof_read == sizeof(pac207_sof_marker)) {
+ PDEBUG(D_STREAM,
+ "SOF found, bytes to analyze: %u."
+ " Frame starts at byte #%u",
+ len, i + 1);
+ sd->sof_read = 0;
+ return m + i + 1;
+ }
+ } else {
+ sd->sof_read = 0;
+ }
+ }
+
+ return NULL;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame,
+ __u8 *data,
+ int len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned char *sof;
+
+ sof = pac207_find_sof(gspca_dev, data, len);
+ if (sof) {
+ int n;
+
+ /* finish decoding current frame */
+ n = sof - data;
+ if (n > sizeof pac207_sof_marker)
+ n -= sizeof pac207_sof_marker;
+ else
+ n = 0;
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, n);
+ sd->header_read = 0;
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
+ len -= sof - data;
+ data = sof;
+ }
+ if (sd->header_read < 11) {
+ int needed;
+
+ /* get average lumination from frame header (byte 5) */
+ if (sd->header_read < 5) {
+ needed = 5 - sd->header_read;
+ if (len >= needed)
+ atomic_set(&sd->avg_lum, data[needed - 1]);
+ }
+ /* skip the rest of the header */
+ needed = 11 - sd->header_read;
+ if (len <= needed) {
+ sd->header_read += len;
+ return;
+ }
+ data += needed;
+ len -= needed;
+ sd->header_read = 11;
+ }
+
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ pac207_write_reg(gspca_dev, 0x08, sd->brightness);
+ pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
+ pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ pac207_write_reg(gspca_dev, 0x02, sd->exposure);
+ pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
+ pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ pac207_write_reg(gspca_dev, 0x0e, sd->gain);
+ pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
+ pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->exposure = val;
+ if (gspca_dev->streaming)
+ setexposure(gspca_dev);
+ return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->exposure;
+ return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gain = val;
+ if (gspca_dev->streaming)
+ setgain(gspca_dev);
+ return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->gain;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ /* when switching to autogain set defaults to make sure
+ we are on a valid point of the autogain gain /
+ exposure knee graph, and give this change time to
+ take effect before doing autogain. */
+ if (sd->autogain) {
+ sd->exposure = PAC207_EXPOSURE_DEFAULT;
+ sd->gain = PAC207_GAIN_DEFAULT;
+ if (gspca_dev->streaming) {
+ sd->autogain_ignore_frames =
+ PAC207_AUTOGAIN_IGNORE_FRAMES;
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+ }
+ }
+
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .dq_callback = pac207_do_auto_gain,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
+ {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")},
+ {USB_DEVICE(0x093a, 0x2463), DVNM("Philips spc200nc pac207")},
+ {USB_DEVICE(0x093a, 0x2464), DVNM("Labtec Webcam 1200")},
+ {USB_DEVICE(0x093a, 0x2468), DVNM("PAC207")},
+ {USB_DEVICE(0x093a, 0x2470), DVNM("Genius GF112")},
+ {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")},
+ {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")},
+ {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
new file mode 100644
index 00000000000..5c052e31be4
--- /dev/null
+++ b/drivers/media/video/gspca/pac7311.c
@@ -0,0 +1,760 @@
+/*
+ * Pixart PAC7311 library
+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "pac7311"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
+MODULE_DESCRIPTION("Pixart PAC7311");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ int avg_lum;
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char autogain;
+
+ char ffseq;
+ signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+#define BRIGHTNESS_MAX 0x20
+ .maximum = BRIGHTNESS_MAX,
+ .step = 1,
+#define BRIGHTNESS_DEF 0x10
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define CONTRAST_DEF 127
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define COLOR_DEF 127
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
+
+static const __u8 pac7311_jpeg_header[] = {
+ 0xff, 0xd8,
+ 0xff, 0xe0, 0x00, 0x03, 0x20,
+ 0xff, 0xc0, 0x00, 0x11, 0x08,
+ 0x01, 0xe0, /* 12: height */
+ 0x02, 0x80, /* 14: width */
+ 0x03, /* 16 */
+ 0x01, 0x21, 0x00,
+ 0x02, 0x11, 0x01,
+ 0x03, 0x11, 0x01,
+ 0xff, 0xdb, 0x00, 0x84,
+ 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
+ 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
+ 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
+ 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
+ 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
+ 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
+ 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
+ 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
+ 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
+ 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
+ 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
+ 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
+ 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
+ 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
+ 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
+ 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
+ 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+ 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
+ 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
+ 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
+ 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
+ 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
+ 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
+ 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
+ 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
+ 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
+ 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
+ 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
+ 0x11, 0x00, 0x3f, 0x00
+};
+
+static void reg_w_buf(struct gspca_dev *gspca_dev,
+ __u16 index,
+ const char *buffer, __u16 len)
+{
+ memcpy(gspca_dev->usb_buf, buffer, len);
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 1, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, len,
+ 500);
+}
+
+static __u8 reg_r(struct gspca_dev *gspca_dev,
+ __u16 index)
+{
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, 1,
+ 500);
+ return gspca_dev->usb_buf[0];
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+ __u16 index,
+ __u8 value)
+{
+ gspca_dev->usb_buf[0] = value;
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, gspca_dev->usb_buf, 1,
+ 500);
+}
+
+/* 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;
+
+ PDEBUG(D_CONF, "Find Sensor PAC7311");
+ reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
+ reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
+ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+ reg_w(gspca_dev, 0xff, 0x04);
+ reg_w(gspca_dev, 0x27, 0x80);
+ reg_w(gspca_dev, 0x28, 0xca);
+ reg_w(gspca_dev, 0x29, 0x53);
+ reg_w(gspca_dev, 0x2a, 0x0e);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x3e, 0x20);
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x05;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ sd->autogain = AUTOGAIN_DEF;
+ return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int brightness;
+
+/*jfm: inverted?*/
+ brightness = BRIGHTNESS_MAX - sd->brightness;
+ reg_w(gspca_dev, 0xff, 0x04);
+/* reg_w(gspca_dev, 0x0e, 0x00); */
+ reg_w(gspca_dev, 0x0f, brightness);
+ /* load registers to sensor (Bit 0, auto clear) */
+ reg_w(gspca_dev, 0x11, 0x01);
+ PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x80, sd->contrast);
+ /* load registers to sensor (Bit 0, auto clear) */
+ reg_w(gspca_dev, 0x11, 0x01);
+ PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x10, sd->colors);
+ /* load registers to sensor (Bit 0, auto clear) */
+ reg_w(gspca_dev, 0x11, 0x01);
+ PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
+ reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
+ reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
+ reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
+ reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
+ reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
+ reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
+ reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
+ reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
+ reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
+ reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
+ reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
+ reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
+ reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
+ reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
+ reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
+ reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
+ reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
+ reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
+ reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
+
+ reg_w(gspca_dev, 0xff, 0x04);
+ reg_w(gspca_dev, 0x02, 0x04);
+ reg_w(gspca_dev, 0x03, 0x54);
+ reg_w(gspca_dev, 0x04, 0x07);
+ reg_w(gspca_dev, 0x05, 0x2b);
+ reg_w(gspca_dev, 0x06, 0x09);
+ reg_w(gspca_dev, 0x07, 0x0f);
+ reg_w(gspca_dev, 0x08, 0x09);
+ reg_w(gspca_dev, 0x09, 0x00);
+ reg_w(gspca_dev, 0x0c, 0x07);
+ reg_w(gspca_dev, 0x0d, 0x00);
+ reg_w(gspca_dev, 0x0e, 0x00);
+ reg_w(gspca_dev, 0x0f, 0x62);
+ reg_w(gspca_dev, 0x10, 0x08);
+ reg_w(gspca_dev, 0x12, 0x07);
+ reg_w(gspca_dev, 0x13, 0x00);
+ reg_w(gspca_dev, 0x14, 0x00);
+ reg_w(gspca_dev, 0x15, 0x00);
+ reg_w(gspca_dev, 0x16, 0x00);
+ reg_w(gspca_dev, 0x17, 0x00);
+ reg_w(gspca_dev, 0x18, 0x00);
+ reg_w(gspca_dev, 0x19, 0x00);
+ reg_w(gspca_dev, 0x1a, 0x00);
+ reg_w(gspca_dev, 0x1b, 0x03);
+ reg_w(gspca_dev, 0x1c, 0xa0);
+ reg_w(gspca_dev, 0x1d, 0x01);
+ reg_w(gspca_dev, 0x1e, 0xf4);
+ reg_w(gspca_dev, 0x21, 0x00);
+ reg_w(gspca_dev, 0x22, 0x08);
+ reg_w(gspca_dev, 0x24, 0x03);
+ reg_w(gspca_dev, 0x26, 0x00);
+ reg_w(gspca_dev, 0x27, 0x01);
+ reg_w(gspca_dev, 0x28, 0xca);
+ reg_w(gspca_dev, 0x29, 0x10);
+ reg_w(gspca_dev, 0x2a, 0x06);
+ reg_w(gspca_dev, 0x2b, 0x78);
+ reg_w(gspca_dev, 0x2c, 0x00);
+ reg_w(gspca_dev, 0x2d, 0x00);
+ reg_w(gspca_dev, 0x2e, 0x00);
+ reg_w(gspca_dev, 0x2f, 0x00);
+ reg_w(gspca_dev, 0x30, 0x23);
+ reg_w(gspca_dev, 0x31, 0x28);
+ reg_w(gspca_dev, 0x32, 0x04);
+ reg_w(gspca_dev, 0x33, 0x11);
+ reg_w(gspca_dev, 0x34, 0x00);
+ reg_w(gspca_dev, 0x35, 0x00);
+ reg_w(gspca_dev, 0x11, 0x01);
+ setcontrast(gspca_dev);
+ setbrightness(gspca_dev);
+ setcolors(gspca_dev);
+
+ /* set correct resolution */
+ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ case 2: /* 160x120 */
+ reg_w(gspca_dev, 0xff, 0x04);
+ reg_w(gspca_dev, 0x02, 0x03);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x08, 0x09);
+ reg_w(gspca_dev, 0x17, 0x20);
+ reg_w(gspca_dev, 0x1b, 0x00);
+/* reg_w(gspca_dev, 0x80, 0x69); */
+ reg_w(gspca_dev, 0x87, 0x10);
+ break;
+ case 1: /* 320x240 */
+ reg_w(gspca_dev, 0xff, 0x04);
+ reg_w(gspca_dev, 0x02, 0x03);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x08, 0x09);
+ reg_w(gspca_dev, 0x17, 0x30);
+/* reg_w(gspca_dev, 0x80, 0x3f); */
+ reg_w(gspca_dev, 0x87, 0x11);
+ break;
+ case 0: /* 640x480 */
+ reg_w(gspca_dev, 0xff, 0x04);
+ reg_w(gspca_dev, 0x02, 0x03);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x08, 0x08);
+ reg_w(gspca_dev, 0x17, 0x00);
+/* reg_w(gspca_dev, 0x80, 0x1c); */
+ reg_w(gspca_dev, 0x87, 0x12);
+ break;
+ }
+
+ /* start stream */
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x78, 0x04);
+ reg_w(gspca_dev, 0x78, 0x05);
+
+ if (sd->autogain) {
+ sd->ag_cnt = AG_CNT_START;
+ sd->avg_lum = 0;
+ } else {
+ sd->ag_cnt = -1;
+ }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, 0xff, 0x04);
+ reg_w(gspca_dev, 0x27, 0x80);
+ reg_w(gspca_dev, 0x28, 0xca);
+ reg_w(gspca_dev, 0x29, 0x53);
+ reg_w(gspca_dev, 0x2a, 0x0e);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x3e, 0x20);
+ reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
+ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, 0xff, 0x04);
+ reg_w(gspca_dev, 0x27, 0x80);
+ reg_w(gspca_dev, 0x28, 0xca);
+ reg_w(gspca_dev, 0x29, 0x53);
+ reg_w(gspca_dev, 0x2a, 0x0e);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x3e, 0x20);
+ reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
+ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+}
+
+static void setautogain(struct gspca_dev *gspca_dev, int luma)
+{
+ int luma_mean = 128;
+ int luma_delta = 20;
+ __u8 spring = 5;
+ int Gbright;
+
+ Gbright = reg_r(gspca_dev, 0x02);
+ PDEBUG(D_FRAM, "luma mean %d", luma);
+ if (luma < luma_mean - luma_delta ||
+ luma > luma_mean + luma_delta) {
+ Gbright += (luma_mean - luma) >> spring;
+ if (Gbright > 0x1a)
+ Gbright = 0x1a;
+ else if (Gbright < 4)
+ Gbright = 4;
+ PDEBUG(D_FRAM, "gbright %d", Gbright);
+ reg_w(gspca_dev, 0xff, 0x04);
+ reg_w(gspca_dev, 0x0f, Gbright);
+ /* load registers to sensor (Bit 0, auto clear) */
+ reg_w(gspca_dev, 0x11, 0x01);
+ }
+}
+
+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;
+ unsigned char tmpbuf[4];
+ int i, p, ffseq;
+
+/* if (len < 5) { */
+ if (len < 6) {
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+
+ ffseq = sd->ffseq;
+
+ for (p = 0; p < len - 6; p++) {
+ if ((data[0 + p] == 0xff)
+ && (data[1 + p] == 0xff)
+ && (data[2 + p] == 0x00)
+ && (data[3 + p] == 0xff)
+ && (data[4 + p] == 0x96)) {
+
+ /* start of frame */
+ if (sd->ag_cnt >= 0 && p > 28) {
+ sd->avg_lum += data[p - 23];
+ if (--sd->ag_cnt < 0) {
+ sd->ag_cnt = AG_CNT_START;
+ setautogain(gspca_dev,
+ sd->avg_lum / AG_CNT_START);
+ sd->avg_lum = 0;
+ }
+ }
+
+ /* copy the end of data to the current frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, p);
+
+ /* put the JPEG header in the new frame */
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ (unsigned char *) pac7311_jpeg_header,
+ 12);
+ tmpbuf[0] = gspca_dev->height >> 8;
+ tmpbuf[1] = gspca_dev->height & 0xff;
+ tmpbuf[2] = gspca_dev->width >> 8;
+ tmpbuf[3] = gspca_dev->width & 0xff;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ tmpbuf, 4);
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ (unsigned char *) &pac7311_jpeg_header[16],
+ PAC7311_JPEG_HEADER_SIZE - 16);
+
+ data += p + 7;
+ len -= p + 7;
+ ffseq = 0;
+ break;
+ }
+ }
+
+ /* remove the 'ff ff ff xx' sequences */
+ switch (ffseq) {
+ case 3:
+ data += 1;
+ len -= 1;
+ break;
+ case 2:
+ if (data[0] == 0xff) {
+ data += 2;
+ len -= 2;
+ frame->data_end -= 2;
+ }
+ break;
+ case 1:
+ if (data[0] == 0xff
+ && data[1] == 0xff) {
+ data += 3;
+ len -= 3;
+ frame->data_end -= 1;
+ }
+ break;
+ }
+ for (i = 0; i < len - 4; i++) {
+ if (data[i] == 0xff
+ && data[i + 1] == 0xff
+ && data[i + 2] == 0xff) {
+ memmove(&data[i], &data[i + 4], len - i - 4);
+ len -= 4;
+ }
+ }
+ ffseq = 0;
+ if (data[len - 4] == 0xff) {
+ if (data[len - 3] == 0xff
+ && data[len - 2] == 0xff) {
+ len -= 4;
+ }
+ } else if (data[len - 3] == 0xff) {
+ if (data[len - 2] == 0xff
+ && data[len - 1] == 0xff)
+ ffseq = 3;
+ } else if (data[len - 2] == 0xff) {
+ if (data[len - 1] == 0xff)
+ ffseq = 2;
+ } else if (data[len - 1] == 0xff)
+ ffseq = 1;
+ sd->ffseq = ffseq;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+/* sd->brightness = reg_r(gspca_dev, 0x08);
+ return sd->brightness; */
+/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
+}
+
+
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+/* getcontrast(gspca_dev); */
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+/* getcolors(gspca_dev); */
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (val) {
+ sd->ag_cnt = AG_CNT_START;
+ sd->avg_lum = 0;
+ } else {
+ sd->ag_cnt = -1;
+ }
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")},
+ {USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")},
+ {USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")},
+ {USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")},
+ {USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera")},
+ /* and also ', Trust WB-3350p, SIGMA cam 2350' */
+ {USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")},
+ {USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
new file mode 100644
index 00000000000..dbeebe8625c
--- /dev/null
+++ b/drivers/media/video/gspca/sonixb.c
@@ -0,0 +1,1477 @@
+/*
+ * sonix sn9c102 (bayer) library
+ * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
+ * Add Pas106 Stefano Mozzi (C) 2004
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sonixb"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 8)
+static const char version[] = "2.1.8";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ struct sd_desc sd_desc; /* our nctrls differ dependend upon the
+ sensor, so we use a per cam copy */
+ atomic_t avg_lum;
+
+ unsigned char gain;
+ unsigned char exposure;
+ unsigned char brightness;
+ unsigned char autogain;
+ unsigned char autogain_ignore_frames;
+ unsigned char freq; /* light freq filter setting */
+ unsigned char saturation;
+ unsigned char hue;
+ unsigned char contrast;
+
+ unsigned char fr_h_sz; /* size of frame header */
+ char sensor; /* Type of image sensor chip */
+#define SENSOR_HV7131R 0
+#define SENSOR_OV6650 1
+#define SENSOR_OV7630 2
+#define SENSOR_OV7630_3 3
+#define SENSOR_PAS106 4
+#define SENSOR_PAS202 5
+#define SENSOR_TAS5110 6
+#define SENSOR_TAS5130CXX 7
+ char sensor_has_gain;
+ __u8 sensor_addr;
+};
+
+#define COMP2 0x8f
+#define COMP 0xc7 /* 0x87 //0x07 */
+#define COMP1 0xc9 /* 0x89 //0x09 */
+
+#define MCK_INIT 0x63
+#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
+
+#define SYS_CLK 0x04
+
+/* We calculate the autogain at the end of the transfer of a frame, at this
+ moment a frame with the old settings is being transmitted, and a frame is
+ being captured with the old settings. So if we adjust the autogain we must
+ ignore atleast the 2 next frames for the new settings to come into effect
+ before doing any other adjustments */
+#define AUTOGAIN_IGNORE_FRAMES 3
+#define AUTOGAIN_DEADZONE 1000
+#define DESIRED_AVG_LUM 7000
+
+/* 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);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 127
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define GAIN_DEF 127
+#define GAIN_KNEE 200
+ .default_value = GAIN_DEF,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
+#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = EXPOSURE_DEF,
+ .flags = 0,
+ },
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic Gain (and Exposure)",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
+ .flags = 0,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light frequency filter",
+ .minimum = 0,
+ .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
+ .step = 1,
+#define FREQ_DEF 1
+ .default_value = FREQ_DEF,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define SATURATION_DEF 127
+ .default_value = SATURATION_DEF,
+ },
+ .set = sd_setsaturation,
+ .get = sd_getsaturation,
+ },
+ {
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define HUE_DEF 127
+ .default_value = HUE_DEF,
+ },
+ .set = sd_sethue,
+ .get = sd_gethue,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define CONTRAST_DEF 127
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+static const __u8 probe_ov7630[] = {0x08, 0x44};
+
+static const __u8 initHv7131[] = {
+ 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
+ 0x28, 0x1e, 0x60, 0x8a, 0x20,
+ 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
+};
+static const __u8 hv7131_sensor_init[][8] = {
+ {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
+ {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
+ {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
+ {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
+ {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
+};
+static const __u8 initOv6650[] = {
+ 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
+ 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
+};
+static const __u8 ov6650_sensor_init[][8] =
+{
+ /* Bright, contrast, etc are set througth SCBB interface.
+ * AVCAP on win2 do not send any data on this controls. */
+ /* Anyway, some registers appears to alter bright and constrat */
+
+ /* Reset sensor */
+ {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
+ /* Set clock register 0x11 low nibble is clock divider */
+ {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
+ /* Next some unknown stuff */
+ {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
+/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
+ * THIS SET GREEN SCREEN
+ * (pixels could be innverted in decode kind of "brg",
+ * but blue wont be there. Avoid this data ... */
+ {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
+ {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
+ {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
+ /* Enable rgb brightness control */
+ {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
+ /* HDG: Note windows uses the line below, which sets both register 0x60
+ and 0x61 I believe these registers of the ov6650 are identical as
+ those of the ov7630, because if this is true the windows settings
+ add a bit additional red gain and a lot additional blue gain, which
+ matches my findings that the windows settings make blue much too
+ blue and red a little too red.
+ {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
+ /* Some more unknown stuff */
+ {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
+ {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
+};
+
+static const __u8 initOv7630[] = {
+ 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
+ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
+ 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
+ 0x28, 0x1e, /* H & V sizes r15 .. r16 */
+ 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
+ 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
+};
+static const __u8 initOv7630_3[] = {
+ 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
+ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
+ 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
+ 0x28, 0x1e, /* H & V sizes r15 .. r16 */
+ 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
+ 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
+ 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
+ 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
+};
+static const __u8 ov7630_sensor_init_com[][8] = {
+ {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
+ {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
+/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
+ {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
+ {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
+ {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
+ {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
+ {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
+ {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
+ {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
+ {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
+ {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
+/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
+ {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
+ {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
+ {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
+ {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
+ {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
+ {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
+};
+static const __u8 ov7630_sensor_init[][8] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
+ {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
+ {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
+ {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
+ {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
+};
+static const __u8 ov7630_sensor_init_3[][8] = {
+ {0xa0, 0x21, 0x2a, 0xa0, 0x00, 0x00, 0x00, 0x10},
+ {0xa0, 0x21, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x10},
+};
+
+static const __u8 initPas106[] = {
+ 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
+ 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
+ 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+};
+/* compression 0x86 mckinit1 0x2b */
+static const __u8 pas106_data[][2] = {
+ {0x02, 0x04}, /* Pixel Clock Divider 6 */
+ {0x03, 0x13}, /* Frame Time MSB */
+/* {0x03, 0x12}, * Frame Time MSB */
+ {0x04, 0x06}, /* Frame Time LSB */
+/* {0x04, 0x05}, * Frame Time LSB */
+ {0x05, 0x65}, /* Shutter Time Line Offset */
+/* {0x05, 0x6d}, * Shutter Time Line Offset */
+/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
+ {0x06, 0xcd}, /* Shutter Time Pixel Offset */
+ {0x07, 0xc1}, /* Black Level Subtract Sign */
+/* {0x07, 0x00}, * Black Level Subtract Sign */
+ {0x08, 0x06}, /* Black Level Subtract Level */
+ {0x08, 0x06}, /* Black Level Subtract Level */
+/* {0x08, 0x01}, * Black Level Subtract Level */
+ {0x09, 0x05}, /* Color Gain B Pixel 5 a */
+ {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
+ {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
+ {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
+ {0x0d, 0x00}, /* Color GainH Pixel */
+ {0x0e, 0x0e}, /* Global Gain */
+ {0x0f, 0x00}, /* Contrast */
+ {0x10, 0x06}, /* H&V synchro polarity */
+ {0x11, 0x06}, /* ?default */
+ {0x12, 0x06}, /* DAC scale */
+ {0x14, 0x02}, /* ?default */
+ {0x13, 0x01}, /* Validate Settings */
+};
+static const __u8 initPas202[] = {
+ 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
+ 0x28, 0x1e, 0x28, 0x89, 0x30,
+ 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
+};
+static const __u8 pas202_sensor_init[][8] = {
+ {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
+ {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
+ {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
+ {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
+ {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
+ {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
+ {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
+ {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
+ {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
+ {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
+ {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
+ {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
+
+ {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
+ {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
+ {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
+ {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
+ {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
+ {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
+ {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
+ {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
+};
+
+static const __u8 initTas5110[] = {
+ 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
+ 0x16, 0x12, 0x60, 0x86, 0x2b,
+ 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
+};
+static const __u8 tas5110_sensor_init[][8] = {
+ {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
+ {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
+ {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
+};
+
+static const __u8 initTas5130[] = {
+ 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
+ 0x28, 0x1e, 0x60, COMP, MCK_INIT,
+ 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+};
+static const __u8 tas5130_sensor_init[][8] = {
+/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
+ * shutter 0x47 short exposure? */
+ {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
+ /* shutter 0x01 long exposure */
+ {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
+};
+
+/* get one byte in gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+ __u16 value)
+{
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value,
+ 0, /* index */
+ gspca_dev->usb_buf, 1,
+ 500);
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+ __u16 value,
+ const __u8 *buffer,
+ int len)
+{
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (len > sizeof gspca_dev->usb_buf) {
+ PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
+ return;
+ }
+#endif
+ memcpy(gspca_dev->usb_buf, buffer, len);
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x08, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value,
+ 0, /* index */
+ gspca_dev->usb_buf, len,
+ 500);
+}
+
+static void reg_w_big(struct gspca_dev *gspca_dev,
+ __u16 value,
+ const __u8 *buffer,
+ int len)
+{
+ __u8 *tmpbuf;
+
+ tmpbuf = kmalloc(len, GFP_KERNEL);
+ memcpy(tmpbuf, buffer, len);
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x08, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value,
+ 0, /* index */
+ tmpbuf, len,
+ 500);
+ kfree(tmpbuf);
+}
+
+static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
+{
+ int retry = 60;
+
+ /* is i2c ready */
+ reg_w(gspca_dev, 0x08, buffer, 8);
+ while (retry--) {
+ msleep(10);
+ reg_r(gspca_dev, 0x08);
+ if (gspca_dev->usb_buf[0] & 0x04) {
+ if (gspca_dev->usb_buf[0] & 0x08)
+ return -1;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static void i2c_w_vector(struct gspca_dev *gspca_dev,
+ const __u8 buffer[][8], int len)
+{
+ for (;;) {
+ reg_w(gspca_dev, 0x08, *buffer, 8);
+ len -= 8;
+ if (len <= 0)
+ break;
+ buffer++;
+ }
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 value;
+
+ switch (sd->sensor) {
+ case SENSOR_OV6650:
+ case SENSOR_OV7630_3:
+ case SENSOR_OV7630: {
+ __u8 i2cOV[] =
+ {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
+
+ /* change reg 0x06 */
+ i2cOV[1] = sd->sensor_addr;
+ i2cOV[3] = sd->brightness;
+ if (i2c_w(gspca_dev, i2cOV) < 0)
+ goto err;
+ break;
+ }
+ case SENSOR_PAS106: {
+ __u8 i2c1[] =
+ {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
+
+ i2c1[3] = sd->brightness >> 3;
+ i2c1[2] = 0x0e;
+ if (i2c_w(gspca_dev, i2c1) < 0)
+ goto err;
+ i2c1[3] = 0x01;
+ i2c1[2] = 0x13;
+ if (i2c_w(gspca_dev, i2c1) < 0)
+ goto err;
+ break;
+ }
+ case SENSOR_PAS202: {
+ /* __u8 i2cpexpo1[] =
+ {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
+ __u8 i2cpexpo[] =
+ {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
+ __u8 i2cp202[] =
+ {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
+ static __u8 i2cpdoit[] =
+ {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
+
+ /* change reg 0x10 */
+ i2cpexpo[4] = 0xff - sd->brightness;
+/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
+ goto err; */
+/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
+ goto err; */
+ if (i2c_w(gspca_dev, i2cpexpo) < 0)
+ goto err;
+ if (i2c_w(gspca_dev, i2cpdoit) < 0)
+ goto err;
+ i2cp202[3] = sd->brightness >> 3;
+ if (i2c_w(gspca_dev, i2cp202) < 0)
+ goto err;
+ if (i2c_w(gspca_dev, i2cpdoit) < 0)
+ goto err;
+ break;
+ }
+ case SENSOR_TAS5130CXX: {
+ __u8 i2c[] =
+ {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
+
+ value = 0xff - sd->brightness;
+ i2c[4] = value;
+ PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
+ if (i2c_w(gspca_dev, i2c) < 0)
+ goto err;
+ break;
+ }
+ case SENSOR_TAS5110:
+ /* FIXME figure out howto control brightness on TAS5110 */
+ break;
+ }
+ return;
+err:
+ PDEBUG(D_ERR, "i2c error brightness");
+}
+
+static void setsensorgain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned char gain = sd->gain;
+
+ switch (sd->sensor) {
+
+ case SENSOR_TAS5110: {
+ __u8 i2c[] =
+ {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
+
+ i2c[4] = 255 - gain;
+ if (i2c_w(gspca_dev, i2c) < 0)
+ goto err;
+ break;
+ }
+
+ case SENSOR_OV6650:
+ gain >>= 1;
+ /* fall thru */
+ case SENSOR_OV7630_3: {
+ __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
+
+ i2c[1] = sd->sensor_addr;
+ i2c[3] = gain >> 2;
+ if (i2c_w(gspca_dev, i2c) < 0)
+ goto err;
+ break;
+ }
+ }
+ return;
+err:
+ PDEBUG(D_ERR, "i2c error gain");
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 gain;
+ __u8 rgb_value;
+
+ gain = sd->gain >> 4;
+
+ /* red and blue gain */
+ rgb_value = gain << 4 | gain;
+ reg_w(gspca_dev, 0x10, &rgb_value, 1);
+ /* green gain */
+ rgb_value = gain;
+ reg_w(gspca_dev, 0x11, &rgb_value, 1);
+
+ if (sd->sensor_has_gain)
+ setsensorgain(gspca_dev);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->sensor) {
+ case SENSOR_TAS5110: {
+ __u8 reg;
+
+ /* register 19's high nibble contains the sn9c10x clock divider
+ The high nibble configures the no fps according to the
+ formula: 60 / high_nibble. With a maximum of 30 fps */
+ reg = 120 * sd->exposure / 1000;
+ if (reg < 2)
+ reg = 2;
+ else if (reg > 15)
+ reg = 15;
+ reg = (reg << 4) | 0x0b;
+ reg_w(gspca_dev, 0x19, &reg, 1);
+ break;
+ }
+ case SENSOR_OV6650:
+ case SENSOR_OV7630_3: {
+ /* The ov6650 / ov7630 have 2 registers which both influence
+ exposure, register 11, whose low nibble sets the nr off fps
+ according to: fps = 30 / (low_nibble + 1)
+
+ The fps configures the maximum exposure setting, but it is
+ possible to use less exposure then what the fps maximum
+ allows by setting register 10. register 10 configures the
+ actual exposure as quotient of the full exposure, with 0
+ being no exposure at all (not very usefull) and reg10_max
+ being max exposure possible at that framerate.
+
+ The code maps our 0 - 510 ms exposure ctrl to these 2
+ registers, trying to keep fps as high as possible.
+ */
+ __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
+ int reg10, reg11;
+ /* ov6645 datasheet says reg10_max is 9a, but that uses
+ tline * 2 * reg10 as formula for calculating texpo, the
+ ov6650 probably uses the same formula as the 7730 which uses
+ tline * 4 * reg10, which explains why the reg10max we've
+ found experimentally for the ov6650 is exactly half that of
+ the ov6645. The ov7630 datasheet says the max is 0x41. */
+ const int reg10_max = (sd->sensor == SENSOR_OV6650)
+ ? 0x4d : 0x41;
+
+ reg11 = (60 * sd->exposure + 999) / 1000;
+ if (reg11 < 1)
+ reg11 = 1;
+ else if (reg11 > 16)
+ reg11 = 16;
+
+ /* frame exposure time in ms = 1000 * reg11 / 30 ->
+ reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
+ reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
+
+ /* Don't allow this to get below 10 when using autogain, the
+ steps become very large (relatively) when below 10 causing
+ the image to oscilate from much too dark, to much too bright
+ and back again. */
+ if (sd->autogain && reg10 < 10)
+ reg10 = 10;
+ else if (reg10 > reg10_max)
+ reg10 = reg10_max;
+
+ /* Write reg 10 and reg11 low nibble */
+ i2c[1] = sd->sensor_addr;
+ i2c[3] = reg10;
+ i2c[4] |= reg11 - 1;
+ if (sd->sensor == SENSOR_OV7630_3) {
+ __u8 reg76 = reg10 & 0x03;
+ __u8 i2c_reg76[] = {0xa0, 0x21, 0x76, 0x00,
+ 0x00, 0x00, 0x00, 0x10};
+ reg10 >>= 2;
+ i2c_reg76[3] = reg76;
+ if (i2c_w(gspca_dev, i2c_reg76) < 0)
+ PDEBUG(D_ERR, "i2c error exposure");
+ }
+ if (i2c_w(gspca_dev, i2c) < 0)
+ PDEBUG(D_ERR, "i2c error exposure");
+ break;
+ }
+ }
+}
+
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->sensor) {
+ case SENSOR_OV6650:
+ case SENSOR_OV7630_3: {
+ /* Framerate adjust register for artificial light 50 hz flicker
+ compensation, identical to ov6630 0x2b register, see ov6630
+ datasheet.
+ 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
+ __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
+ switch (sd->freq) {
+ default:
+/* case 0: * no filter*/
+/* case 2: * 60 hz */
+ i2c[3] = 0;
+ break;
+ case 1: /* 50 hz */
+ i2c[3] = (sd->sensor == SENSOR_OV6650)
+ ? 0x4f : 0x8a;
+ break;
+ }
+ i2c[1] = sd->sensor_addr;
+ if (i2c_w(gspca_dev, i2c) < 0)
+ PDEBUG(D_ERR, "i2c error setfreq");
+ break;
+ }
+ }
+}
+
+static void setsaturation(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->sensor) {
+/* case SENSOR_OV6650: */
+ case SENSOR_OV7630_3:
+ case SENSOR_OV7630: {
+ __u8 i2c[] = {0xa0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10};
+ i2c[1] = sd->sensor_addr;
+ i2c[3] = sd->saturation & 0xf0;
+ if (i2c_w(gspca_dev, i2c) < 0)
+ PDEBUG(D_ERR, "i2c error setsaturation");
+ else
+ PDEBUG(D_CONF, "saturation set to: %d",
+ (int)sd->saturation);
+ break;
+ }
+ }
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->sensor) {
+/* case SENSOR_OV6650: */
+ case SENSOR_OV7630_3:
+ case SENSOR_OV7630: {
+ __u8 i2c[] = {0xa0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10};
+ i2c[1] = sd->sensor_addr;
+ i2c[3] = 0x20 | (sd->hue >> 3);
+ if (i2c_w(gspca_dev, i2c) < 0)
+ PDEBUG(D_ERR, "i2c error setsaturation");
+ else
+ PDEBUG(D_CONF, "hue set to: %d", (int)sd->hue);
+ break;
+ }
+ }
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->sensor) {
+/* case SENSOR_OV6650: */
+ case SENSOR_OV7630_3:
+ case SENSOR_OV7630: {
+ __u8 i2c[] = {0xa0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10};
+ i2c[1] = sd->sensor_addr;
+ i2c[3] = 0x20 | (sd->contrast >> 3);
+ if (i2c_w(gspca_dev, i2c) < 0)
+ PDEBUG(D_ERR, "i2c error setcontrast");
+ else
+ PDEBUG(D_CONF, "contrast set to: %d",
+ (int)sd->contrast);
+ break;
+ }
+ }
+}
+
+
+static void do_autogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int avg_lum = atomic_read(&sd->avg_lum);
+
+ if (avg_lum == -1)
+ return;
+
+ if (sd->autogain_ignore_frames > 0)
+ sd->autogain_ignore_frames--;
+ else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
+ sd->brightness * DESIRED_AVG_LUM / 127,
+ AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
+ PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
+ (int)sd->gain, (int)sd->exposure);
+ sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
+ }
+}
+
+/* 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;
+ __u16 product;
+ int sif = 0;
+
+ /* nctrls depends upon the sensor, so we use a per cam copy */
+ memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
+ gspca_dev->sd_desc = &sd->sd_desc;
+
+ sd->fr_h_sz = 12; /* default size of the frame header */
+ sd->sd_desc.nctrls = 2; /* default nb of ctrls */
+ sd->autogain = AUTOGAIN_DEF; /* default is autogain active */
+
+ product = id->idProduct;
+/* switch (id->idVendor) { */
+/* case 0x0c45: * Sonix */
+ switch (product) {
+ case 0x6001: /* SN9C102 */
+ case 0x6005: /* SN9C101 */
+ case 0x6007: /* SN9C101 */
+ sd->sensor = SENSOR_TAS5110;
+ sd->sensor_has_gain = 1;
+ sd->sd_desc.nctrls = 4;
+ sd->sd_desc.dq_callback = do_autogain;
+ sif = 1;
+ break;
+ case 0x6009: /* SN9C101 */
+ case 0x600d: /* SN9C101 */
+ case 0x6029: /* SN9C101 */
+ sd->sensor = SENSOR_PAS106;
+ sif = 1;
+ break;
+ case 0x6011: /* SN9C101 - SN9C101G */
+ sd->sensor = SENSOR_OV6650;
+ sd->sensor_has_gain = 1;
+ sd->sensor_addr = 0x60;
+ sd->sd_desc.nctrls = 5;
+ sd->sd_desc.dq_callback = do_autogain;
+ sif = 1;
+ break;
+ case 0x6019: /* SN9C101 */
+ case 0x602c: /* SN9C102 */
+ case 0x602e: /* SN9C102 */
+ sd->sensor = SENSOR_OV7630;
+ sd->sensor_addr = 0x21;
+ break;
+ case 0x60b0: /* SN9C103 */
+ sd->sensor = SENSOR_OV7630_3;
+ sd->sensor_addr = 0x21;
+ sd->fr_h_sz = 18; /* size of frame header */
+ sd->sensor_has_gain = 1;
+ sd->sd_desc.nctrls = 8;
+ sd->sd_desc.dq_callback = do_autogain;
+ sd->autogain = 0;
+ break;
+ case 0x6024: /* SN9C102 */
+ case 0x6025: /* SN9C102 */
+ sd->sensor = SENSOR_TAS5130CXX;
+ break;
+ case 0x6028: /* SN9C102 */
+ sd->sensor = SENSOR_PAS202;
+ break;
+ case 0x602d: /* SN9C102 */
+ sd->sensor = SENSOR_HV7131R;
+ break;
+ case 0x60af: /* SN9C103 */
+ sd->sensor = SENSOR_PAS202;
+ sd->fr_h_sz = 18; /* size of frame header (?) */
+ break;
+ }
+/* break; */
+/* } */
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ if (!sif) {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+ if (sd->sensor == SENSOR_OV7630_3) {
+ /* We only have 320x240 & 640x480 */
+ cam->cam_mode++;
+ cam->nmodes--;
+ }
+ } else {
+ cam->cam_mode = sif_mode;
+ cam->nmodes = ARRAY_SIZE(sif_mode);
+ }
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->gain = GAIN_DEF;
+ sd->exposure = EXPOSURE_DEF;
+ sd->freq = FREQ_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->saturation = SATURATION_DEF;
+ sd->hue = HUE_DEF;
+ if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
+ reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ reg_r(gspca_dev, 0x00);
+ if (gspca_dev->usb_buf[0] != 0x10)
+ return -ENODEV;
+ return 0;
+}
+
+static void pas106_i2cinit(struct gspca_dev *gspca_dev)
+{
+ int i;
+ const __u8 *data;
+ __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
+
+ i = ARRAY_SIZE(pas106_data);
+ data = pas106_data[0];
+ while (--i >= 0) {
+ memcpy(&i2c1[2], data, 2);
+ /* copy 2 bytes from the template */
+ if (i2c_w(gspca_dev, i2c1) < 0)
+ PDEBUG(D_ERR, "i2c error pas106");
+ data += 2;
+ }
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int mode, l;
+ const __u8 *sn9c10x;
+ __u8 reg01, reg17;
+ __u8 reg17_19[3];
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ sn9c10x = initHv7131;
+ reg17_19[0] = 0x60;
+ reg17_19[1] = (mode << 4) | 0x8a;
+ reg17_19[2] = 0x20;
+ break;
+ case SENSOR_OV6650:
+ sn9c10x = initOv6650;
+ reg17_19[0] = 0x68;
+ reg17_19[1] = (mode << 4) | 0x8b;
+ reg17_19[2] = 0x20;
+ break;
+ case SENSOR_OV7630:
+ sn9c10x = initOv7630;
+ reg17_19[0] = 0x68;
+ reg17_19[1] = (mode << 4) | COMP2;
+ reg17_19[2] = MCK_INIT1;
+ break;
+ case SENSOR_OV7630_3:
+ sn9c10x = initOv7630_3;
+ reg17_19[0] = 0x68;
+ reg17_19[1] = (mode << 4) | COMP2;
+ reg17_19[2] = MCK_INIT1;
+ break;
+ case SENSOR_PAS106:
+ sn9c10x = initPas106;
+ reg17_19[0] = 0x24; /* 0x28 */
+ reg17_19[1] = (mode << 4) | COMP1;
+ reg17_19[2] = MCK_INIT1;
+ break;
+ case SENSOR_PAS202:
+ sn9c10x = initPas202;
+ reg17_19[0] = mode ? 0x24 : 0x20;
+ reg17_19[1] = (mode << 4) | 0x89;
+ reg17_19[2] = 0x20;
+ break;
+ case SENSOR_TAS5110:
+ sn9c10x = initTas5110;
+ reg17_19[0] = 0x60;
+ reg17_19[1] = (mode << 4) | 0x86;
+ reg17_19[2] = 0x2b; /* 0xf3; */
+ break;
+ default:
+/* case SENSOR_TAS5130CXX: */
+ sn9c10x = initTas5130;
+ reg17_19[0] = 0x60;
+ reg17_19[1] = (mode << 4) | COMP;
+ reg17_19[2] = mode ? 0x23 : 0x43;
+ break;
+ }
+ switch (sd->sensor) {
+ case SENSOR_OV7630:
+ reg01 = 0x06;
+ reg17 = 0x29;
+ l = sizeof initOv7630;
+ break;
+ case SENSOR_OV7630_3:
+ reg01 = 0x44;
+ reg17 = 0x68;
+ l = sizeof initOv7630_3;
+ break;
+ default:
+ reg01 = sn9c10x[0];
+ reg17 = sn9c10x[0x17 - 1];
+ l = 0x1f;
+ break;
+ }
+
+ /* reg 0x01 bit 2 video transfert on */
+ reg_w(gspca_dev, 0x01, &reg01, 1);
+ /* reg 0x17 SensorClk enable inv Clk 0x60 */
+ reg_w(gspca_dev, 0x17, &reg17, 1);
+/*fixme: for ov7630 102
+ reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
+ /* Set the registers from the template */
+ reg_w_big(gspca_dev, 0x01, sn9c10x, l);
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ i2c_w_vector(gspca_dev, hv7131_sensor_init,
+ sizeof hv7131_sensor_init);
+ break;
+ case SENSOR_OV6650:
+ i2c_w_vector(gspca_dev, ov6650_sensor_init,
+ sizeof ov6650_sensor_init);
+ break;
+ case SENSOR_OV7630:
+ i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
+ sizeof ov7630_sensor_init_com);
+ msleep(200);
+ i2c_w_vector(gspca_dev, ov7630_sensor_init,
+ sizeof ov7630_sensor_init);
+ break;
+ case SENSOR_OV7630_3:
+ i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
+ sizeof ov7630_sensor_init_com);
+ msleep(200);
+ i2c_w(gspca_dev, ov7630_sensor_init_3[mode]);
+ break;
+ case SENSOR_PAS106:
+ pas106_i2cinit(gspca_dev);
+ break;
+ case SENSOR_PAS202:
+ i2c_w_vector(gspca_dev, pas202_sensor_init,
+ sizeof pas202_sensor_init);
+ break;
+ case SENSOR_TAS5110:
+ i2c_w_vector(gspca_dev, tas5110_sensor_init,
+ sizeof tas5110_sensor_init);
+ break;
+ default:
+/* case SENSOR_TAS5130CXX: */
+ i2c_w_vector(gspca_dev, tas5130_sensor_init,
+ sizeof tas5130_sensor_init);
+ break;
+ }
+ /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
+ reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
+ /* compression register */
+ reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
+ /* H_start */
+ reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
+ /* V_START */
+ reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
+ /* reset 0x17 SensorClk enable inv Clk 0x60 */
+ /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
+ reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
+ /*MCKSIZE ->3 */ /*fixme: not ov7630*/
+ reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
+ /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
+ reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
+ /* Enable video transfert */
+ reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
+ /* Compression */
+ reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
+ msleep(20);
+
+ setgain(gspca_dev);
+ setbrightness(gspca_dev);
+ setexposure(gspca_dev);
+ setfreq(gspca_dev);
+ setsaturation(gspca_dev);
+ sethue(gspca_dev);
+ setcontrast(gspca_dev);
+
+ sd->autogain_ignore_frames = 0;
+ atomic_set(&sd->avg_lum, -1);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ __u8 ByteSend;
+
+ ByteSend = 0x09; /* 0X00 */
+ reg_w(gspca_dev, 0x01, &ByteSend, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ unsigned char *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ int i;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* frames start with:
+ * ff ff 00 c4 c4 96 synchro
+ * 00 (unknown)
+ * xx (frame sequence / size / compression)
+ * (xx) (idem - extra byte for sn9c103)
+ * ll mm brightness sum inside auto exposure
+ * ll mm brightness sum outside auto exposure
+ * (xx xx xx xx xx) audio values for snc103
+ */
+ if (len > 6 && len < 24) {
+ for (i = 0; i < len - 6; i++) {
+ if (data[0 + i] == 0xff
+ && data[1 + i] == 0xff
+ && data[2 + i] == 0x00
+ && data[3 + i] == 0xc4
+ && data[4 + i] == 0xc4
+ && data[5 + i] == 0x96) { /* start of frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET,
+ frame, data, 0);
+ if (len - i < sd->fr_h_sz) {
+ atomic_set(&sd->avg_lum, -1);
+ PDEBUG(D_STREAM, "packet too short to"
+ " get avg brightness");
+ } else if (sd->fr_h_sz == 12) {
+ atomic_set(&sd->avg_lum,
+ data[i + 8] +
+ (data[i + 9] << 8));
+ } else {
+ atomic_set(&sd->avg_lum,
+ data[i + 9] +
+ (data[i + 10] << 8));
+ }
+ data += i + sd->fr_h_sz;
+ len -= i + sd->fr_h_sz;
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ frame, data, len);
+ return;
+ }
+ }
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET,
+ frame, data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gain = val;
+ if (gspca_dev->streaming)
+ setgain(gspca_dev);
+ return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->gain;
+ return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->exposure = val;
+ if (gspca_dev->streaming)
+ setexposure(gspca_dev);
+ return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->exposure;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ /* when switching to autogain set defaults to make sure
+ we are on a valid point of the autogain gain /
+ exposure knee graph, and give this change time to
+ take effect before doing autogain. */
+ if (sd->autogain) {
+ sd->exposure = EXPOSURE_DEF;
+ sd->gain = GAIN_DEF;
+ if (gspca_dev->streaming) {
+ sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+ }
+ }
+
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+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)
+ setfreq(gspca_dev);
+ return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->freq;
+ return 0;
+}
+
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->saturation = val;
+ if (gspca_dev->streaming)
+ setsaturation(gspca_dev);
+ return 0;
+}
+
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->saturation;
+ return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hue = val;
+ if (gspca_dev->streaming)
+ sethue(gspca_dev);
+ return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->hue;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+ strcpy((char *) menu->name, "NoFliker");
+ return 0;
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+#ifndef CONFIG_USB_SN9C102
+ {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
+ {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
+ {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
+ {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
+ {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
+#endif
+ {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
+#ifndef CONFIG_USB_SN9C102
+ {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
+ {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
+ {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
+ {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
+ {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
+ {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
+ {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
+ {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
+ {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
+ {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
+#endif
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
new file mode 100644
index 00000000000..3e68b992695
--- /dev/null
+++ b/drivers/media/video/gspca/sonixj.c
@@ -0,0 +1,1671 @@
+/*
+ * Sonix sn9c102p sn9c105 sn9c120 (jpeg) library
+ * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sonixj"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ int avg_lum;
+ unsigned int exposure;
+
+ unsigned short brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char autogain;
+
+ signed char ag_cnt;
+#define AG_CNT_START 13
+
+ char qindex;
+ unsigned char bridge;
+#define BRIDGE_SN9C102P 0
+#define BRIDGE_SN9C105 1
+#define BRIDGE_SN9C110 2
+#define BRIDGE_SN9C120 3
+#define BRIDGE_SN9C325 4
+ char sensor; /* Type of image sensor chip */
+#define SENSOR_HV7131R 0
+#define SENSOR_MI0360 1
+#define SENSOR_MO4000 2
+#define SENSOR_OV7648 3
+#define SENSOR_OV7660 4
+ unsigned char i2c_base;
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 0xffff,
+ .step = 1,
+#define BRIGHTNESS_DEF 0x7fff
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+#define CONTRAST_DEF 63
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define COLOR_DEF 127
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/*Data from sn9c102p+hv71331r */
+static const __u8 sn_hv7131[] = {
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */
+ 0x00, 0x03, 0x64, 0x00, 0x1A, 0x20, 0x20, 0x20, 0xA1, 0x11,
+/* rega regb regc regd rege regf reg10 reg11 */
+ 0x02, 0x09, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, /* 00 */
+/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
+ 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, 0x0a, 0x00, 0x00, 0x00,
+/* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const __u8 sn_mi0360[] = {
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */
+ 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xb1, 0x5d,
+/* rega regb regc regd rege regf reg10 reg11 */
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,
+/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
+ 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, 0x06, 0x00, 0x00, 0x00,
+/* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const __u8 sn_mo4000[] = {
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */
+ 0x12, 0x23, 0x60, 0x00, 0x1A, 0x00, 0x20, 0x18, 0x81,
+/* reg9 rega regb regc regd rege regf reg10 reg11*/
+ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/
+ 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40, 0x08, 0x00, 0x00,
+/* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x25, 0x39, 0x4b,
+ 0x5c, 0x6b, 0x79, 0x87, 0x95, 0xa2, 0xaf, 0xbb, 0xc7,
+ 0xd3, 0xdf, 0xea, 0xf5
+};
+
+static const __u8 sn_ov7648[] = {
+ 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xA1, 0x6E, 0x18, 0x65,
+ 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1E, 0x82,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const __u8 sn_ov7660[] = {
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */
+ 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x81,
+/* reg9 rega regb regc regd rege regf reg10 reg11*/
+ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/
+ 0x01, 0x01, 0x14, 0x28, 0x1e, 0x00, 0x07, 0x00, 0x00,
+/* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* sequence specific to the sensors - !! index = SENSOR_xxx */
+static const __u8 *sn_tb[] = {
+ sn_hv7131,
+ sn_mi0360,
+ sn_mo4000,
+ sn_ov7648,
+ sn_ov7660
+};
+
+static const __u8 regsn20[] = {
+ 0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
+ 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
+};
+static const __u8 regsn20_sn9c120[] = {
+ 0x00, 0x25, 0x3c, 0x50, 0x62, 0x72, 0x81, 0x90,
+ 0x9e, 0xab, 0xb8, 0xc5, 0xd1, 0xdd, 0xe9, 0xf4, 0xff
+};
+static const __u8 regsn20_sn9c325[] = {
+ 0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
+ 0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
+};
+
+static const __u8 reg84[] = {
+ 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
+ 0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
+/* 0x00, 0x00, 0x00, 0x00, 0x00 */
+ 0xf7, 0x0f, 0x0a, 0x00, 0x00
+};
+static const __u8 reg84_sn9c120_1[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x00, 0x00
+};
+static const __u8 reg84_sn9c120_2[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x02, 0x3b
+};
+static const __u8 reg84_sn9c120_3[] = {
+ 0x14, 0x00, 0x27, 0x00, 0x08, 0x00, 0xeb, 0x0f,
+ 0xd5, 0x0f, 0x42, 0x00, 0x41, 0x00, 0xca, 0x0f,
+ 0xf5, 0x0f, 0x0c, 0x02, 0x3b
+};
+static const __u8 reg84_sn9c325[] = {
+ 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
+ 0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
+ 0xf8, 0x0f, 0x00, 0x00, 0x00
+};
+
+static const __u8 hv7131r_sensor_init[][8] = {
+ {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
+ {0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
+ {0xD1, 0x11, 0x40, 0xFF, 0x7F, 0x7F, 0x7F, 0x10},
+ {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x11, 0x14, 0x01, 0xE2, 0x02, 0x82, 0x10},
+ {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+
+ {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xC1, 0x11, 0x25, 0x00, 0x61, 0xA8, 0x00, 0x10},
+ {0xA1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10},
+ {0xC1, 0x11, 0x31, 0x20, 0x2E, 0x20, 0x00, 0x10},
+ {0xC1, 0x11, 0x25, 0x00, 0xC3, 0x50, 0x00, 0x10},
+ {0xA1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */
+ {0xC1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */
+
+ {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
+
+ {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
+ {}
+};
+static const __u8 mi0360_sensor_init[][8] = {
+ {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x0D, 0x00, 0x01, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
+ {0xD1, 0x5D, 0x03, 0x01, 0xE2, 0x02, 0x82, 0x10},
+ {0xD1, 0x5D, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10},
+ {0xB1, 0x5D, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
+ {0xD1, 0x5D, 0x2F, 0xF7, 0xB0, 0x00, 0x04, 0x10},
+ {0xD1, 0x5D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
+ {0xB1, 0x5D, 0x3D, 0x06, 0x8F, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x40, 0x01, 0xE0, 0x00, 0xD1, 0x10},
+ {0xB1, 0x5D, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
+ {0xD1, 0x5D, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x5E, 0x00, 0x00, 0xA3, 0x1D, 0x10},
+ {0xB1, 0x5D, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
+
+ {0xB1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x2B, 0x00, 0xA0, 0x00, 0xB0, 0x10},
+ {0xD1, 0x5D, 0x2D, 0x00, 0xA0, 0x00, 0xA0, 0x10},
+
+ {0xB1, 0x5D, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */
+ {0xB1, 0x5D, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
+
+ {0xD1, 0x5D, 0x2B, 0x00, 0xB9, 0x00, 0xE3, 0x10},
+ {0xD1, 0x5D, 0x2D, 0x00, 0x5f, 0x00, 0xB9, 0x10}, /* 42 */
+/* {0xB1, 0x5D, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */
+/* {0xB1, 0x5D, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */
+ {0xB1, 0x5D, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
+ {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
+ {}
+};
+static const __u8 mo4000_sensor_init[][8] = {
+ {0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x06, 0x80, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x06, 0x81, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x11, 0x20, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x11, 0x30, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+ {}
+};
+static const __u8 ov7660_sensor_init[][8] = {
+ {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
+ {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
+ /* Outformat ?? rawRGB */
+ {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
+ {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10},
+/* {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10}, */
+ /* GAIN BLUE RED VREF */
+ {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10},
+ /* COM 1 BAVE GEAVE AECHH */
+ {0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */
+ {0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */
+ {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10},
+/* {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10}, */
+ /* AECH CLKRC COM7 COM8 */
+ {0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */
+ {0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10},
+ /* HSTART HSTOP VSTRT VSTOP */
+ {0xa1, 0x21, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x10}, /* PSHFT */
+ {0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */
+ {0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10},
+ /* BOS GBOS GROS ROS (BGGR offset) */
+ {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10},
+/* {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10}, */
+ /* AEW AEB VPT BBIAS */
+ {0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10},
+ /* GbBIAS RSVD EXHCH EXHCL */
+ {0xd1, 0x21, 0x2c, 0x80, 0x00, 0x00, 0x62, 0x10},
+ /* RBIAS ADVFL ASDVFH YAVE */
+ {0xc1, 0x21, 0x30, 0x08, 0x30, 0xb4, 0x00, 0x10},
+ /* HSYST HSYEN HREF */
+ {0xd1, 0x21, 0x33, 0x00, 0x07, 0x84, 0x00, 0x10}, /* reserved */
+ {0xd1, 0x21, 0x37, 0x0c, 0x02, 0x43, 0x00, 0x10},
+ /* ADC ACOM OFON TSLB */
+ {0xd1, 0x21, 0x3b, 0x02, 0x6c, 0x19, 0x0e, 0x10},
+ /* COM11 COM12 COM13 COM14 */
+ {0xd1, 0x21, 0x3f, 0x41, 0xc1, 0x22, 0x08, 0x10},
+ /* EDGE COM15 COM16 COM17 */
+ {0xd1, 0x21, 0x43, 0xf0, 0x10, 0x78, 0xa8, 0x10}, /* reserved */
+ {0xd1, 0x21, 0x47, 0x60, 0x80, 0x00, 0x00, 0x10}, /* reserved */
+ {0xd1, 0x21, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* reserved */
+ {0xd1, 0x21, 0x4f, 0x46, 0x36, 0x0f, 0x17, 0x10}, /* MTX 1 2 3 4 */
+ {0xd1, 0x21, 0x53, 0x7f, 0x96, 0x40, 0x40, 0x10}, /* MTX 5 6 7 8 */
+ {0xb1, 0x21, 0x57, 0x40, 0x0f, 0x00, 0x00, 0x10}, /* MTX9 MTXS */
+ {0xd1, 0x21, 0x59, 0xba, 0x9a, 0x22, 0xb9, 0x10}, /* reserved */
+ {0xd1, 0x21, 0x5d, 0x9b, 0x10, 0xf0, 0x05, 0x10}, /* reserved */
+ {0xa1, 0x21, 0x61, 0x60, 0x00, 0x00, 0x00, 0x10}, /* reserved */
+ {0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10},
+ /* LCC1 LCC2 LCC3 LCC4 */
+ {0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */
+ {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10},
+ {0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10},
+ /* band gap reference [0..3] DBLV */
+ {0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */
+ {0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */
+ {0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */
+ {0xd1, 0x21, 0x78, 0x34, 0x30, 0x2f, 0x2b, 0x10}, /* gamma curve */
+ {0xd1, 0x21, 0x7c, 0x03, 0x07, 0x17, 0x34, 0x10}, /* gamma curve */
+ {0xd1, 0x21, 0x80, 0x41, 0x4d, 0x58, 0x63, 0x10}, /* gamma curve */
+ {0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */
+ {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
+ {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
+ {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10},
+/****** (some exchanges in the win trace) ******/
+ {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
+ /* bits[3..0]reserved */
+ {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+ /* VREF vertical frame ctrl */
+ {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* 0x20 */
+ {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
+/* {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, */
+ {0xa1, 0x21, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10},
+ {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10},
+/****** (some exchanges in the win trace) ******/
+ {0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */
+ {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10},/* dummy line low */
+ {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10},
+/****** (some exchanges in the win trace) ******/
+/**********startsensor KO if changed !!****/
+ {0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10},
+/* here may start the isoc exchanges */
+ {}
+};
+/* reg0x04 reg0x07 reg 0x10 */
+/* expo = (COM1 & 0x02) | (AECHH & 0x2f <<10) [ (AECh << 2) */
+
+static const __u8 ov7648_sensor_init[][8] = {
+ {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+ {0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00},
+ {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+ {0xA1, 0x6E, 0x3F, 0x20, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x04, 0x02, 0xB1, 0x02, 0x39, 0x10},
+ {0xD1, 0x6E, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x0C, 0x02, 0x7F, 0x01, 0xE0, 0x10},
+ {0xD1, 0x6E, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10},
+ {0xD1, 0x6E, 0x16, 0x85, 0x40, 0x4A, 0x40, 0x10},
+ {0xC1, 0x6E, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x1D, 0x08, 0x03, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x23, 0x00, 0xB0, 0x00, 0x94, 0x10},
+ {0xD1, 0x6E, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x2D, 0x14, 0x35, 0x61, 0x84, 0x10},
+ {0xD1, 0x6E, 0x31, 0xA2, 0xBD, 0xD8, 0xFF, 0x10},
+ {0xD1, 0x6E, 0x35, 0x06, 0x1E, 0x12, 0x02, 0x10},
+ {0xD1, 0x6E, 0x39, 0xAA, 0x53, 0x37, 0xD5, 0x10},
+ {0xA1, 0x6E, 0x3D, 0xF2, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x3E, 0x00, 0x00, 0x80, 0x03, 0x10},
+ {0xD1, 0x6E, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10},
+ {0xC1, 0x6E, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10},
+ {0xD1, 0x6E, 0x4B, 0x02, 0xEF, 0x08, 0xCD, 0x10},
+ {0xD1, 0x6E, 0x4F, 0x00, 0xD0, 0x00, 0xA0, 0x10},
+ {0xD1, 0x6E, 0x53, 0x01, 0xAA, 0x01, 0x40, 0x10},
+ {0xD1, 0x6E, 0x5A, 0x50, 0x04, 0x30, 0x03, 0x10},
+ {0xA1, 0x6E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x5F, 0x10, 0x40, 0xFF, 0x00, 0x10},
+ /* {0xD1, 0x6E, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * This is currently setting a
+ * blue tint, and some things more , i leave it here for future test if
+ * somene is having problems with color on this sensor
+ {0xD1, 0x6E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xC1, 0x6E, 0x73, 0x10, 0x80, 0xEB, 0x00, 0x10},
+ {0xA1, 0x6E, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x15, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xC1, 0x6E, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10},
+ {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x07, 0xB5, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x18, 0x6B, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x07, 0xB8, 0x00, 0x00, 0x00, 0x10}, */
+ {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+ {0xA1, 0x6E, 0x06, 0x03, 0x00, 0x00, 0x00, 0x10}, /* Bright... */
+ {0xA1, 0x6E, 0x07, 0x66, 0x00, 0x00, 0x00, 0x10}, /* B.. */
+ {0xC1, 0x6E, 0x1A, 0x03, 0x65, 0x90, 0x00, 0x10}, /* Bright/Witen....*/
+/* {0xC1, 0x6E, 0x16, 0x45, 0x40, 0x60, 0x00, 0x10}, * Bright/Witene */
+ {}
+};
+
+static const __u8 qtable4[] = {
+ 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06,
+ 0x06, 0x08, 0x0A, 0x11,
+ 0x0A, 0x0A, 0x08, 0x08, 0x0A, 0x15, 0x0F, 0x0F, 0x0C, 0x11, 0x19, 0x15,
+ 0x19, 0x19, 0x17, 0x15,
+ 0x17, 0x17, 0x1B, 0x1D, 0x25, 0x21, 0x1B, 0x1D, 0x23, 0x1D, 0x17, 0x17,
+ 0x21, 0x2E, 0x21, 0x23,
+ 0x27, 0x29, 0x2C, 0x2C, 0x2C, 0x19, 0x1F, 0x30, 0x32, 0x2E, 0x29, 0x32,
+ 0x25, 0x29, 0x2C, 0x29,
+ 0x06, 0x08, 0x08, 0x0A, 0x08, 0x0A, 0x13, 0x0A, 0x0A, 0x13, 0x29, 0x1B,
+ 0x17, 0x1B, 0x29, 0x29,
+ 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+ 0x29, 0x29, 0x29, 0x29,
+ 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+ 0x29, 0x29, 0x29, 0x29,
+ 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+ 0x29, 0x29, 0x29, 0x29
+};
+
+/* read <len> bytes (len < sizeof gspca_dev->usb_buf) to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+ __u16 value, int len)
+{
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, 0,
+ gspca_dev->usb_buf, len,
+ 500);
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+ __u16 value,
+ const __u8 *buffer,
+ int len)
+{
+ if (len <= sizeof gspca_dev->usb_buf) {
+ memcpy(gspca_dev->usb_buf, buffer, len);
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, 0,
+ gspca_dev->usb_buf, len,
+ 500);
+ } else {
+ __u8 *tmpbuf;
+
+ tmpbuf = kmalloc(len, GFP_KERNEL);
+ memcpy(tmpbuf, buffer, len);
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, 0,
+ tmpbuf, len,
+ 500);
+ kfree(tmpbuf);
+ }
+}
+
+/* I2C write 2 bytes */
+static void i2c_w2(struct gspca_dev *gspca_dev,
+ const __u8 *buffer)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 mode[8];
+
+ /* is i2c ready */
+ mode[0] = 0x81 | (2 << 4);
+ mode[1] = sd->i2c_base;
+ mode[2] = buffer[0];
+ mode[3] = buffer[1];
+ mode[4] = 0;
+ mode[5] = 0;
+ mode[6] = 0;
+ mode[7] = 0x10;
+ reg_w(gspca_dev, 0x08, mode, 8);
+}
+
+/* I2C write 8 bytes */
+static void i2c_w8(struct gspca_dev *gspca_dev,
+ const __u8 *buffer)
+{
+ reg_w(gspca_dev, 0x08, buffer, 8);
+ msleep(1);
+}
+
+/* read 5 bytes in gspca_dev->usb_buf */
+static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 mode[8];
+
+ mode[0] = 0x81 | 0x10;
+ mode[1] = sd->i2c_base;
+ mode[2] = reg;
+ mode[3] = 0;
+ mode[4] = 0;
+ mode[5] = 0;
+ mode[6] = 0;
+ mode[7] = 0x10;
+ i2c_w8(gspca_dev, mode);
+ mode[0] = 0x81 | (5 << 4) | 0x02;
+ mode[2] = 0;
+ i2c_w8(gspca_dev, mode);
+ reg_r(gspca_dev, 0x0a, 5);
+}
+
+static int probesensor(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 reg02;
+ static const __u8 datasend[] = { 2, 0 };
+ /* reg val1 val2 val3 val4 */
+
+ i2c_w2(gspca_dev, datasend);
+/* should write 0xa1 0x11 0x02 0x00 0x00 0x00 0x00 the 0x10 is add by i2cw */
+ msleep(10);
+ reg02 = 0x66;
+ reg_w(gspca_dev, 0x02, &reg02, 1); /* Gpio on */
+ msleep(10);
+ i2c_r5(gspca_dev, 0); /* read sensor id */
+ if (gspca_dev->usb_buf[0] == 0x02
+ && gspca_dev->usb_buf[1] == 0x09
+ && gspca_dev->usb_buf[2] == 0x01
+ && gspca_dev->usb_buf[3] == 0x00
+ && gspca_dev->usb_buf[4] == 0x00) {
+ PDEBUG(D_PROBE, "Find Sensor sn9c102P HV7131R");
+ sd->sensor = SENSOR_HV7131R;
+ return SENSOR_HV7131R;
+ }
+ PDEBUG(D_PROBE, "Find Sensor %d %d %d",
+ gspca_dev->usb_buf[0], gspca_dev->usb_buf[1],
+ gspca_dev->usb_buf[2]);
+ PDEBUG(D_PROBE, "Sensor sn9c102P Not found");
+ return -ENODEV;
+}
+
+static int configure_gpio(struct gspca_dev *gspca_dev,
+ const __u8 *sn9c1xx)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 data;
+ __u8 regF1;
+ const __u8 *reg9a;
+ static const __u8 reg9a_def[] =
+ {0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
+ static const __u8 reg9a_sn9c120[] = /* from win trace */
+ {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
+ static const __u8 reg9a_sn9c325[] =
+ {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
+
+
+ regF1 = 0x00;
+ reg_w(gspca_dev, 0xf1, &regF1, 1);
+ reg_w(gspca_dev, 0x01, &sn9c1xx[0], 1); /*fixme:jfm was [1] en v1*/
+
+ /* configure gpio */
+ reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
+ reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
+ reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); /* jfm was 3 */
+ switch (sd->bridge) {
+ case BRIDGE_SN9C325:
+ reg9a = reg9a_sn9c325;
+ break;
+ case BRIDGE_SN9C120:
+ reg9a = reg9a_sn9c120;
+ break;
+ default:
+ reg9a = reg9a_def;
+ break;
+ }
+ reg_w(gspca_dev, 0x9a, reg9a, 6);
+
+ data = 0x60; /*fixme:jfm 60 00 00 (3) */
+ reg_w(gspca_dev, 0xd4, &data, 1);
+
+ reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
+
+ switch (sd->bridge) {
+ case BRIDGE_SN9C120: /* from win trace */
+ data = 0x61;
+ reg_w(gspca_dev, 0x01, &data, 1);
+ data = 0x20;
+ reg_w(gspca_dev, 0x17, &data, 1);
+ data = 0x60;
+ reg_w(gspca_dev, 0x01, &data, 1);
+ break;
+ case BRIDGE_SN9C325:
+ data = 0x43;
+ reg_w(gspca_dev, 0x01, &data, 1);
+ data = 0xae;
+ reg_w(gspca_dev, 0x17, &data, 1);
+ data = 0x42;
+ reg_w(gspca_dev, 0x01, &data, 1);
+ break;
+ default:
+ data = 0x43;
+ reg_w(gspca_dev, 0x01, &data, 1);
+ data = 0x61;
+ reg_w(gspca_dev, 0x17, &data, 1);
+ data = 0x42;
+ reg_w(gspca_dev, 0x01, &data, 1);
+ }
+
+ if (sd->sensor == SENSOR_HV7131R) {
+ if (probesensor(gspca_dev) < 0)
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void hv7131R_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+ static const __u8 SetSensorClk[] = /* 0x08 Mclk */
+ { 0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10 };
+
+ while (hv7131r_sensor_init[i][0]) {
+ i2c_w8(gspca_dev, hv7131r_sensor_init[i]);
+ i++;
+ }
+ i2c_w8(gspca_dev, SetSensorClk);
+}
+
+static void mi0360_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+
+ while (mi0360_sensor_init[i][0]) {
+ i2c_w8(gspca_dev, mi0360_sensor_init[i]);
+ i++;
+ }
+}
+
+static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+
+ while (mo4000_sensor_init[i][0]) {
+ i2c_w8(gspca_dev, mo4000_sensor_init[i]);
+ i++;
+ }
+}
+
+static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+
+ while (ov7648_sensor_init[i][0]) {
+ i2c_w8(gspca_dev, ov7648_sensor_init[i]);
+ i++;
+ }
+}
+
+static void ov7660_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+
+ while (ov7660_sensor_init[i][0]) {
+ i2c_w8(gspca_dev, ov7660_sensor_init[i]);
+ i++;
+ }
+}
+
+/* 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;
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ sd->sensor = -1;
+ switch (vendor) {
+ case 0x0458: /* Genius */
+/* switch (product) {
+ case 0x7025: */
+ sd->bridge = BRIDGE_SN9C120;
+ sd->sensor = SENSOR_MI0360;
+ sd->i2c_base = 0x5d;
+/* break;
+ } */
+ break;
+ case 0x045e:
+/* switch (product) {
+ case 0x00f5:
+ case 0x00f7: */
+ sd->bridge = BRIDGE_SN9C105;
+ sd->sensor = SENSOR_OV7660;
+ sd->i2c_base = 0x21;
+/* break;
+ } */
+ break;
+ case 0x0471: /* Philips */
+/* switch (product) {
+ case 0x0327:
+ case 0x0328:
+ case 0x0330: */
+ sd->bridge = BRIDGE_SN9C105;
+ sd->sensor = SENSOR_MI0360;
+ sd->i2c_base = 0x5d;
+/* break;
+ } */
+ break;
+ case 0x0c45: /* Sonix */
+ switch (product) {
+ case 0x6040:
+ sd->bridge = BRIDGE_SN9C102P;
+/* sd->sensor = SENSOR_MI0360; * from BW600.inf */
+/*fixme: MI0360 base=5d ? */
+ sd->sensor = SENSOR_HV7131R; /* gspcav1 value */
+ sd->i2c_base = 0x11;
+ break;
+/* case 0x607a: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C102P;
+ sd->sensor = SENSOR_OV7648;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x607c:
+ sd->bridge = BRIDGE_SN9C102P;
+ sd->sensor = SENSOR_HV7131R;
+ sd->i2c_base = 0x11;
+ break;
+/* case 0x607e: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C102P;
+ sd->sensor = SENSOR_OV7630;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x60c0:
+ sd->bridge = BRIDGE_SN9C105;
+ sd->sensor = SENSOR_MI0360;
+ sd->i2c_base = 0x5d;
+ break;
+/* case 0x60c8: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C105;
+ sd->sensor = SENSOR_OM6801;
+ sd->i2c_base = 0x??;
+ break; */
+/* case 0x60cc: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C105;
+ sd->sensor = SENSOR_HV7131GP;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x60ec:
+ sd->bridge = BRIDGE_SN9C105;
+ sd->sensor = SENSOR_MO4000;
+ sd->i2c_base = 0x21;
+ break;
+/* case 0x60ef: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C105;
+ sd->sensor = SENSOR_ICM105C;
+ sd->i2c_base = 0x??;
+ break; */
+/* case 0x60fa: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C105;
+ sd->sensor = SENSOR_OV7648;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x60fb:
+ sd->bridge = BRIDGE_SN9C105;
+ sd->sensor = SENSOR_OV7660;
+ sd->i2c_base = 0x21;
+ break;
+ case 0x60fc:
+ sd->bridge = BRIDGE_SN9C105;
+ sd->sensor = SENSOR_HV7131R;
+ sd->i2c_base = 0x11;
+ break;
+/* case 0x60fe: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C105;
+ sd->sensor = SENSOR_OV7630;
+ sd->i2c_base = 0x??;
+ break; */
+/* case 0x6108: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C120;
+ sd->sensor = SENSOR_OM6801;
+ sd->i2c_base = 0x??;
+ break; */
+/* case 0x6122: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C110;
+ sd->sensor = SENSOR_ICM105C;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x612a:
+/* sd->bridge = BRIDGE_SN9C110; * in BW600.inf */
+ sd->bridge = BRIDGE_SN9C325;
+ sd->sensor = SENSOR_OV7648;
+ sd->i2c_base = 0x21;
+/*fixme: sensor_init has base = 00 et 6e!*/
+ break;
+/* case 0x6123: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C110;
+ sd->sensor = SENSOR_SanyoCCD;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x612c:
+ sd->bridge = BRIDGE_SN9C110;
+ sd->sensor = SENSOR_MO4000;
+ sd->i2c_base = 0x21;
+ break;
+/* case 0x612e: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C110;
+ sd->sensor = SENSOR_OV7630;
+ sd->i2c_base = 0x??;
+ break; */
+/* case 0x612f: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C110;
+ sd->sensor = SENSOR_ICM105C;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x6130:
+ sd->bridge = BRIDGE_SN9C120;
+ sd->sensor = SENSOR_MI0360;
+ sd->i2c_base = 0x5d;
+ break;
+ case 0x6138:
+ sd->bridge = BRIDGE_SN9C120;
+ sd->sensor = SENSOR_MO4000;
+ sd->i2c_base = 0x21;
+ break;
+/* case 0x613a: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C120;
+ sd->sensor = SENSOR_OV7648;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x613b:
+ sd->bridge = BRIDGE_SN9C120;
+ sd->sensor = SENSOR_OV7660;
+ sd->i2c_base = 0x21;
+ break;
+ case 0x613c:
+ sd->bridge = BRIDGE_SN9C120;
+ sd->sensor = SENSOR_HV7131R;
+ sd->i2c_base = 0x11;
+ break;
+/* case 0x613e: * from BW600.inf
+ sd->bridge = BRIDGE_SN9C120;
+ sd->sensor = SENSOR_OV7630;
+ sd->i2c_base = 0x??;
+ break; */
+ }
+ break;
+ }
+ if (sd->sensor < 0) {
+ PDEBUG(D_ERR, "Invalid vendor/product %04x:%04x",
+ vendor, product);
+ return -EINVAL;
+ }
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+
+ sd->qindex = 4; /* set the quantization table */
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ sd->autogain = AUTOGAIN_DEF;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+/* const __u8 *sn9c1xx; */
+ __u8 regF1;
+ __u8 regGpio[] = { 0x29, 0x74 };
+
+ /* setup a selector by bridge */
+ regF1 = 0x01;
+ reg_w(gspca_dev, 0xf1, &regF1, 1);
+ reg_r(gspca_dev, 0x00, 1); /* -> regF1 = 0x00 */
+ regF1 = gspca_dev->usb_buf[0];
+ reg_w(gspca_dev, 0xf1, &regF1, 1);
+ reg_r(gspca_dev, 0x00, 1);
+ regF1 = gspca_dev->usb_buf[0];
+ switch (sd->bridge) {
+ case BRIDGE_SN9C102P:
+ if (regF1 != 0x11)
+ return -ENODEV;
+ reg_w(gspca_dev, 0x02, &regGpio[1], 1);
+ break;
+ case BRIDGE_SN9C105:
+ if (regF1 != 0x11)
+ return -ENODEV;
+ reg_w(gspca_dev, 0x02, regGpio, 2);
+ break;
+ case BRIDGE_SN9C110:
+ if (regF1 != 0x12)
+ return -ENODEV;
+ regGpio[1] = 0x62;
+ reg_w(gspca_dev, 0x02, &regGpio[1], 1);
+ break;
+ case BRIDGE_SN9C120:
+ if (regF1 != 0x12)
+ return -ENODEV;
+ regGpio[1] = 0x70;
+ reg_w(gspca_dev, 0x02, regGpio, 2);
+ break;
+ default:
+/* case BRIDGE_SN9C325: */
+ if (regF1 != 0x12)
+ return -ENODEV;
+ regGpio[1] = 0x62;
+ reg_w(gspca_dev, 0x02, &regGpio[1], 1);
+ break;
+ }
+
+ regF1 = 0x01;
+ reg_w(gspca_dev, 0xf1, &regF1, 1);
+
+ return 0;
+}
+
+static unsigned int setexposure(struct gspca_dev *gspca_dev,
+ unsigned int expo)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ static const __u8 doit[] = /* update sensor */
+ { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
+ static const __u8 sensorgo[] = /* sensor on */
+ { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 };
+ static const __u8 gainMo[] =
+ { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
+
+ switch (sd->sensor) {
+ case SENSOR_HV7131R: {
+ __u8 Expodoit[] =
+ { 0xc1, 0x11, 0x25, 0x07, 0x27, 0xc0, 0x00, 0x16 };
+
+ Expodoit[3] = expo >> 16;
+ Expodoit[4] = expo >> 8;
+ Expodoit[5] = expo;
+ i2c_w8(gspca_dev, Expodoit);
+ break;
+ }
+ case SENSOR_MI0360: {
+ __u8 expoMi[] = /* exposure 0x0635 -> 4 fp/s 0x10 */
+ { 0xb1, 0x5d, 0x09, 0x06, 0x35, 0x00, 0x00, 0x16 };
+
+ if (expo > 0x0635)
+ expo = 0x0635;
+ else if (expo < 0x0001)
+ expo = 0x0001;
+ expoMi[3] = expo >> 8;
+ expoMi[4] = expo;
+ i2c_w8(gspca_dev, expoMi);
+ i2c_w8(gspca_dev, doit);
+ i2c_w8(gspca_dev, sensorgo);
+ break;
+ }
+ case SENSOR_MO4000: {
+ __u8 expoMof[] =
+ { 0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10 };
+ __u8 expoMo10[] =
+ { 0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10 };
+
+ if (expo > 0x1fff)
+ expo = 0x1fff;
+ else if (expo < 0x0001)
+ expo = 0x0001;
+ expoMof[3] = (expo & 0x03fc) >> 2;
+ i2c_w8(gspca_dev, expoMof);
+ expoMo10[3] = ((expo & 0x1c00) >> 10)
+ | ((expo & 0x0003) << 4);
+ i2c_w8(gspca_dev, expoMo10);
+ i2c_w8(gspca_dev, gainMo);
+ PDEBUG(D_CONF, "set exposure %d",
+ ((expoMo10[3] & 0x07) << 10)
+ | (expoMof[3] << 2)
+ | ((expoMo10[3] & 0x30) >> 4));
+ break;
+ }
+ }
+ return expo;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned int expo;
+ __u8 k2;
+
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ expo = sd->brightness << 4;
+ if (expo > 0x002dc6c0)
+ expo = 0x002dc6c0;
+ else if (expo < 0x02a0)
+ expo = 0x02a0;
+ sd->exposure = setexposure(gspca_dev, expo);
+ break;
+ case SENSOR_MI0360:
+ expo = sd->brightness >> 4;
+ sd->exposure = setexposure(gspca_dev, expo);
+ break;
+ case SENSOR_MO4000:
+ expo = sd->brightness >> 4;
+ sd->exposure = setexposure(gspca_dev, expo);
+ break;
+ case SENSOR_OV7660:
+ return; /*jfm??*/
+ }
+
+ k2 = sd->brightness >> 10;
+ reg_w(gspca_dev, 0x96, &k2, 1);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 k2;
+ __u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 };
+
+ if (sd->sensor == SENSOR_OV7660)
+ return; /*jfm??*/
+ k2 = sd->contrast;
+ contrast[2] = k2;
+ contrast[0] = (k2 + 1) >> 1;
+ contrast[4] = (k2 + 1) / 5;
+ reg_w(gspca_dev, 0x84, contrast, 6);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 data;
+ int colour;
+
+ colour = sd->colors - 128;
+ if (colour > 0)
+ data = (colour + 32) & 0x7f; /* blue */
+ else
+ data = (-colour + 32) & 0x7f; /* red */
+ reg_w(gspca_dev, 0x05, &data, 1);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ __u8 data;
+ __u8 reg1;
+ __u8 reg17;
+ const __u8 *sn9c1xx;
+ int mode;
+ static const __u8 DC29[] = { 0x6a, 0x50, 0x00, 0x00, 0x50, 0x3c };
+ static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
+ static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
+ static const __u8 CA_sn9c120[] =
+ { 0x14, 0xec, 0x0a, 0xf6 }; /* SN9C120 */
+ static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */
+ static const __u8 CE_sn9c325[] =
+ { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */
+
+ sn9c1xx = sn_tb[(int) sd->sensor];
+ configure_gpio(gspca_dev, sn9c1xx);
+
+/*fixme:jfm this sequence should appear at end of sd_start */
+/* with
+ data = 0x44;
+ reg_w(gspca_dev, 0x01, &data, 1); */
+ reg_w(gspca_dev, 0x15, &sn9c1xx[0x15], 1);
+ reg_w(gspca_dev, 0x16, &sn9c1xx[0x16], 1);
+ reg_w(gspca_dev, 0x12, &sn9c1xx[0x12], 1);
+ reg_w(gspca_dev, 0x13, &sn9c1xx[0x13], 1);
+ reg_w(gspca_dev, 0x18, &sn9c1xx[0x18], 1);
+ reg_w(gspca_dev, 0xd2, &DC29[0], 1);
+ reg_w(gspca_dev, 0xd3, &DC29[1], 1);
+ reg_w(gspca_dev, 0xc6, &DC29[2], 1);
+ reg_w(gspca_dev, 0xc7, &DC29[3], 1);
+ reg_w(gspca_dev, 0xc8, &DC29[4], 1);
+ reg_w(gspca_dev, 0xc9, &DC29[5], 1);
+/*fixme:jfm end of ending sequence */
+ reg_w(gspca_dev, 0x18, &sn9c1xx[0x18], 1);
+ switch (sd->bridge) {
+ case BRIDGE_SN9C325:
+ data = 0xae;
+ break;
+ case BRIDGE_SN9C120:
+ data = 0xa0;
+ break;
+ default:
+ data = 0x60;
+ break;
+ }
+ reg_w(gspca_dev, 0x17, &data, 1);
+ reg_w(gspca_dev, 0x05, &sn9c1xx[5], 1);
+ reg_w(gspca_dev, 0x07, &sn9c1xx[7], 1);
+ reg_w(gspca_dev, 0x06, &sn9c1xx[6], 1);
+ reg_w(gspca_dev, 0x14, &sn9c1xx[0x14], 1);
+ switch (sd->bridge) {
+ case BRIDGE_SN9C325:
+ reg_w(gspca_dev, 0x20, regsn20_sn9c325,
+ sizeof regsn20_sn9c325);
+ for (i = 0; i < 8; i++)
+ reg_w(gspca_dev, 0x84, reg84_sn9c325,
+ sizeof reg84_sn9c325);
+ data = 0x0a;
+ reg_w(gspca_dev, 0x9a, &data, 1);
+ data = 0x60;
+ reg_w(gspca_dev, 0x99, &data, 1);
+ break;
+ case BRIDGE_SN9C120:
+ reg_w(gspca_dev, 0x20, regsn20_sn9c120,
+ sizeof regsn20_sn9c120);
+ for (i = 0; i < 2; i++)
+ reg_w(gspca_dev, 0x84, reg84_sn9c120_1,
+ sizeof reg84_sn9c120_1);
+ for (i = 0; i < 6; i++)
+ reg_w(gspca_dev, 0x84, reg84_sn9c120_2,
+ sizeof reg84_sn9c120_2);
+ reg_w(gspca_dev, 0x84, reg84_sn9c120_3,
+ sizeof reg84_sn9c120_3);
+ data = 0x05;
+ reg_w(gspca_dev, 0x9a, &data, 1);
+ data = 0x5b;
+ reg_w(gspca_dev, 0x99, &data, 1);
+ break;
+ default:
+ reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20);
+ for (i = 0; i < 8; i++)
+ reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
+ data = 0x08;
+ reg_w(gspca_dev, 0x9a, &data, 1);
+ data = 0x59;
+ reg_w(gspca_dev, 0x99, &data, 1);
+ break;
+ }
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ reg1 = 0x02;
+ reg17 = 0x61;
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ hv7131R_InitSensor(gspca_dev);
+ if (mode)
+ reg1 = 0x46; /* 320 clk 48Mhz */
+ else
+ reg1 = 0x06; /* 640 clk 24Mz */
+ break;
+ case SENSOR_MI0360:
+ mi0360_InitSensor(gspca_dev);
+ if (mode)
+ reg1 = 0x46; /* 320 clk 48Mhz */
+ else
+ reg1 = 0x06; /* 640 clk 24Mz */
+ break;
+ case SENSOR_MO4000:
+ mo4000_InitSensor(gspca_dev);
+ if (mode) {
+/* reg1 = 0x46; * 320 clk 48Mhz 60fp/s */
+ reg1 = 0x06; /* clk 24Mz */
+ } else {
+ reg17 = 0x22; /* 640 MCKSIZE */
+ reg1 = 0x06; /* 640 clk 24Mz */
+ }
+ break;
+ case SENSOR_OV7648:
+ reg17 = 0xa2;
+ reg1 = 0x44;
+ ov7648_InitSensor(gspca_dev);
+/* if (mode)
+ ; * 320x2...
+ else
+ ; * 640x... */
+ break;
+ default:
+/* case SENSOR_OV7660: */
+ ov7660_InitSensor(gspca_dev);
+ if (mode) {
+/* reg17 = 0x21; * 320 */
+/* reg1 = 0x44; */
+ reg1 = 0x46;
+ } else {
+ reg17 = 0xa2; /* 640 */
+ reg1 = 0x40;
+ }
+ break;
+ }
+ reg_w(gspca_dev, 0xc0, C0, 6);
+ switch (sd->bridge) {
+ case BRIDGE_SN9C120: /*jfm ?? */
+ reg_w(gspca_dev, 0xca, CA_sn9c120, 4);
+ break;
+ default:
+ reg_w(gspca_dev, 0xca, CA, 4);
+ break;
+ }
+ switch (sd->bridge) {
+ case BRIDGE_SN9C120: /*jfm ?? */
+ case BRIDGE_SN9C325:
+ reg_w(gspca_dev, 0xce, CE_sn9c325, 4);
+ break;
+ default:
+ reg_w(gspca_dev, 0xce, CE, 4);
+ /* ?? {0x1e, 0xdd, 0x2d, 0xe7} */
+ break;
+ }
+
+ /* here change size mode 0 -> VGA; 1 -> CIF */
+ data = 0x40 | sn9c1xx[0x18] | (mode << 4);
+ reg_w(gspca_dev, 0x18, &data, 1);
+
+ reg_w(gspca_dev, 0x100, qtable4, 0x40);
+ reg_w(gspca_dev, 0x140, qtable4 + 0x40, 0x40);
+
+ data = sn9c1xx[0x18] | (mode << 4);
+ reg_w(gspca_dev, 0x18, &data, 1);
+
+ reg_w(gspca_dev, 0x17, &reg17, 1);
+ reg_w(gspca_dev, 0x01, &reg1, 1);
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ static const __u8 stophv7131[] =
+ { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 };
+ static const __u8 stopmi0360[] =
+ { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
+ __u8 regF1;
+ __u8 data;
+ const __u8 *sn9c1xx;
+
+ data = 0x0b;
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ i2c_w8(gspca_dev, stophv7131);
+ data = 0x2b;
+ break;
+ case SENSOR_MI0360:
+ i2c_w8(gspca_dev, stopmi0360);
+ data = 0x29;
+ break;
+ case SENSOR_MO4000:
+ break;
+ case SENSOR_OV7648:
+ data = 0x29;
+ break;
+ default:
+/* case SENSOR_OV7660: */
+ break;
+ }
+ sn9c1xx = sn_tb[(int) sd->sensor];
+ reg_w(gspca_dev, 0x01, &sn9c1xx[1], 1);
+ reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 1);
+ reg_w(gspca_dev, 0x01, &sn9c1xx[1], 1);
+ reg_w(gspca_dev, 0x01, &data, 1);
+ regF1 = 0x01;
+ reg_w(gspca_dev, 0xf1, &regF1, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ /* Thanks S., without your advice, autobright should not work :) */
+ int delta;
+ int expotimes = 0;
+ __u8 luma_mean = 130;
+ __u8 luma_delta = 20;
+
+ delta = sd->avg_lum;
+ if (delta < luma_mean - luma_delta ||
+ delta > luma_mean + luma_delta) {
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ expotimes = sd->exposure >> 8;
+ expotimes += (luma_mean - delta) >> 4;
+ if (expotimes < 0)
+ expotimes = 0;
+ sd->exposure = setexposure(gspca_dev,
+ (unsigned int) (expotimes << 8));
+ break;
+ case SENSOR_MO4000:
+ case SENSOR_MI0360:
+ expotimes = sd->exposure;
+ expotimes += (luma_mean - delta) >> 6;
+ if (expotimes < 0)
+ expotimes = 0;
+ sd->exposure = setexposure(gspca_dev,
+ (unsigned int) expotimes);
+ setcolors(gspca_dev);
+ break;
+ }
+ }
+}
+
+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;
+ int sof, avg_lum;
+
+ sof = len - 64;
+ if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9) {
+
+ /* end of frame */
+ gspca_frame_add(gspca_dev, LAST_PACKET,
+ frame, data, sof + 2);
+ if (sd->ag_cnt < 0)
+ return;
+ if (--sd->ag_cnt >= 0)
+ return;
+ sd->ag_cnt = AG_CNT_START;
+/* w1 w2 w3 */
+/* w4 w5 w6 */
+/* w7 w8 */
+/* w4 */
+ avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6;
+/* w6 */
+ avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6;
+/* w2 */
+ avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6;
+/* w8 */
+ avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6;
+/* w5 */
+ avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
+ avg_lum >>= 4;
+ sd->avg_lum = avg_lum;
+ PDEBUG(D_PACK, "mean lum %d", avg_lum);
+ setautogain(gspca_dev);
+ return;
+ }
+ if (gspca_dev->last_packet_type == LAST_PACKET) {
+
+ /* put the JPEG 422 header */
+ jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static unsigned int getexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 hexpo, mexpo, lexpo;
+
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ /* read sensor exposure */
+ i2c_r5(gspca_dev, 0x25);
+ return (gspca_dev->usb_buf[0] << 16)
+ | (gspca_dev->usb_buf[1] << 8)
+ | gspca_dev->usb_buf[2];
+ case SENSOR_MI0360:
+ /* read sensor exposure */
+ i2c_r5(gspca_dev, 0x09);
+ return (gspca_dev->usb_buf[0] << 8)
+ | gspca_dev->usb_buf[1];
+ case SENSOR_MO4000:
+ i2c_r5(gspca_dev, 0x0e);
+ hexpo = 0; /* gspca_dev->usb_buf[1] & 0x07; */
+ mexpo = 0x40; /* gspca_dev->usb_buf[2] & 0xff; */
+ lexpo = (gspca_dev->usb_buf[1] & 0x30) >> 4;
+ PDEBUG(D_CONF, "exposure %d",
+ (hexpo << 10) | (mexpo << 2) | lexpo);
+ return (hexpo << 10) | (mexpo << 2) | lexpo;
+ default:
+/* case SENSOR_OV7660: */
+ /* read sensor exposure */
+ i2c_r5(gspca_dev, 0x04);
+ hexpo = gspca_dev->usb_buf[3] & 0x2f;
+ lexpo = gspca_dev->usb_buf[0] & 0x02;
+ i2c_r5(gspca_dev, 0x08);
+ mexpo = gspca_dev->usb_buf[2];
+ return (hexpo << 10) | (mexpo << 2) | lexpo;
+ }
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* hardcoded registers seem not readable */
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+/* sd->brightness = 0x7fff; */
+ sd->brightness = getexposure(gspca_dev) >> 4;
+ break;
+ case SENSOR_MI0360:
+ sd->brightness = getexposure(gspca_dev) << 4;
+ break;
+ case SENSOR_MO4000:
+/* sd->brightness = 0x1fff; */
+ sd->brightness = getexposure(gspca_dev) << 4;
+ break;
+ }
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (val)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+#ifndef CONFIG_USB_SN9C102
+ {USB_DEVICE(0x0458, 0x7025), DVNM("Genius Eye 311Q")},
+ {USB_DEVICE(0x045e, 0x00f5), DVNM("MicroSoft VX3000")},
+ {USB_DEVICE(0x045e, 0x00f7), DVNM("MicroSoft VX1000")},
+ {USB_DEVICE(0x0471, 0x0327), DVNM("Philips SPC 600 NC")},
+ {USB_DEVICE(0x0471, 0x0328), DVNM("Philips SPC 700 NC")},
+#endif
+ {USB_DEVICE(0x0471, 0x0330), DVNM("Philips SPC 710NC")},
+ {USB_DEVICE(0x0c45, 0x6040), DVNM("Speed NVC 350K")},
+ {USB_DEVICE(0x0c45, 0x607c), DVNM("Sonix sn9c102p Hv7131R")},
+ {USB_DEVICE(0x0c45, 0x60c0), DVNM("Sangha Sn535")},
+ {USB_DEVICE(0x0c45, 0x60ec), DVNM("SN9C105+MO4000")},
+ {USB_DEVICE(0x0c45, 0x60fb), DVNM("Surfer NoName")},
+ {USB_DEVICE(0x0c45, 0x60fc), DVNM("LG-LIC300")},
+ {USB_DEVICE(0x0c45, 0x612a), DVNM("Avant Camera")},
+ {USB_DEVICE(0x0c45, 0x612c), DVNM("Typhoon Rasy Cam 1.3MPix")},
+#ifndef CONFIG_USB_SN9C102
+ {USB_DEVICE(0x0c45, 0x6130), DVNM("Sonix Pccam")},
+ {USB_DEVICE(0x0c45, 0x6138), DVNM("Sn9c120 Mo4000")},
+ {USB_DEVICE(0x0c45, 0x613b), DVNM("Surfer SN-206")},
+ {USB_DEVICE(0x0c45, 0x613c), DVNM("Sonix Pccam168")},
+#endif
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ info("v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
new file mode 100644
index 00000000000..15620611879
--- /dev/null
+++ b/drivers/media/video/gspca/spca500.c
@@ -0,0 +1,1216 @@
+/*
+ * SPCA500 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "spca500"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ __u8 packet[ISO_MAX_SIZE + 128];
+ /* !! no more than 128 ff in an ISO packet */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+
+ char qindex;
+ char subtype;
+#define AgfaCl20 0
+#define AiptekPocketDV 1
+#define BenqDC1016 2
+#define CreativePCCam300 3
+#define DLinkDSC350 4
+#define Gsmartmini 5
+#define IntelPocketPCCamera 6
+#define KodakEZ200 7
+#define LogitechClickSmart310 8
+#define LogitechClickSmart510 9
+#define LogitechTraveler 10
+#define MustekGsmart300 11
+#define Optimedia 12
+#define PalmPixDC85 13
+#define ToptroIndus 14
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 127
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+#define CONTRAST_DEF 31
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+#define COLOR_DEF 31
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/* Frame packet header offsets for the spca500 */
+#define SPCA500_OFFSET_PADDINGLB 2
+#define SPCA500_OFFSET_PADDINGHB 3
+#define SPCA500_OFFSET_MODE 4
+#define SPCA500_OFFSET_IMGWIDTH 5
+#define SPCA500_OFFSET_IMGHEIGHT 6
+#define SPCA500_OFFSET_IMGMODE 7
+#define SPCA500_OFFSET_QTBLINDEX 8
+#define SPCA500_OFFSET_FRAMSEQ 9
+#define SPCA500_OFFSET_CDSPINFO 10
+#define SPCA500_OFFSET_GPIO 11
+#define SPCA500_OFFSET_AUGPIO 12
+#define SPCA500_OFFSET_DATA 16
+
+
+static const __u16 spca500_visual_defaults[][3] = {
+ {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync,
+ * hue (H byte) = 0,
+ * saturation/hue enable,
+ * brightness/contrast enable.
+ */
+ {0x00, 0x0000, 0x8167}, /* brightness = 0 */
+ {0x00, 0x0020, 0x8168}, /* contrast = 0 */
+ {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync,
+ * hue (H byte) = 0, saturation/hue enable,
+ * brightness/contrast enable.
+ * was 0x0003, now 0x0000.
+ */
+ {0x00, 0x0000, 0x816a}, /* hue (L byte) = 0 */
+ {0x00, 0x0020, 0x8169}, /* saturation = 0x20 */
+ {0x00, 0x0050, 0x8157}, /* edge gain high threshold */
+ {0x00, 0x0030, 0x8158}, /* edge gain low threshold */
+ {0x00, 0x0028, 0x8159}, /* edge bandwidth high threshold */
+ {0x00, 0x000a, 0x815a}, /* edge bandwidth low threshold */
+ {0x00, 0x0001, 0x8202}, /* clock rate compensation = 1/25 sec/frame */
+ {0x0c, 0x0004, 0x0000},
+ /* set interface */
+ {}
+};
+static const __u16 Clicksmart510_defaults[][3] = {
+ {0x00, 0x00, 0x8211},
+ {0x00, 0x01, 0x82c0},
+ {0x00, 0x10, 0x82cb},
+ {0x00, 0x0f, 0x800d},
+ {0x00, 0x82, 0x8225},
+ {0x00, 0x21, 0x8228},
+ {0x00, 0x00, 0x8203},
+ {0x00, 0x00, 0x8204},
+ {0x00, 0x08, 0x8205},
+ {0x00, 0xf8, 0x8206},
+ {0x00, 0x28, 0x8207},
+ {0x00, 0xa0, 0x8208},
+ {0x00, 0x08, 0x824a},
+ {0x00, 0x08, 0x8214},
+ {0x00, 0x80, 0x82c1},
+ {0x00, 0x00, 0x82c2},
+ {0x00, 0x00, 0x82ca},
+ {0x00, 0x80, 0x82c1},
+ {0x00, 0x04, 0x82c2},
+ {0x00, 0x00, 0x82ca},
+ {0x00, 0xfc, 0x8100},
+ {0x00, 0xfc, 0x8105},
+ {0x00, 0x30, 0x8101},
+ {0x00, 0x00, 0x8102},
+ {0x00, 0x00, 0x8103},
+ {0x00, 0x66, 0x8107},
+ {0x00, 0x00, 0x816b},
+ {0x00, 0x00, 0x8155},
+ {0x00, 0x01, 0x8156},
+ {0x00, 0x60, 0x8157},
+ {0x00, 0x40, 0x8158},
+ {0x00, 0x0a, 0x8159},
+ {0x00, 0x06, 0x815a},
+ {0x00, 0x00, 0x813f},
+ {0x00, 0x00, 0x8200},
+ {0x00, 0x19, 0x8201},
+ {0x00, 0x00, 0x82c1},
+ {0x00, 0xa0, 0x82c2},
+ {0x00, 0x00, 0x82ca},
+ {0x00, 0x00, 0x8117},
+ {0x00, 0x00, 0x8118},
+ {0x00, 0x65, 0x8119},
+ {0x00, 0x00, 0x811a},
+ {0x00, 0x00, 0x811b},
+ {0x00, 0x55, 0x811c},
+ {0x00, 0x65, 0x811d},
+ {0x00, 0x55, 0x811e},
+ {0x00, 0x16, 0x811f},
+ {0x00, 0x19, 0x8120},
+ {0x00, 0x80, 0x8103},
+ {0x00, 0x83, 0x816b},
+ {0x00, 0x25, 0x8168},
+ {0x00, 0x01, 0x820f},
+ {0x00, 0xff, 0x8115},
+ {0x00, 0x48, 0x8116},
+ {0x00, 0x50, 0x8151},
+ {0x00, 0x40, 0x8152},
+ {0x00, 0x78, 0x8153},
+ {0x00, 0x40, 0x8154},
+ {0x00, 0x00, 0x8167},
+ {0x00, 0x20, 0x8168},
+ {0x00, 0x00, 0x816a},
+ {0x00, 0x03, 0x816b},
+ {0x00, 0x20, 0x8169},
+ {0x00, 0x60, 0x8157},
+ {0x00, 0x00, 0x8190},
+ {0x00, 0x00, 0x81a1},
+ {0x00, 0x00, 0x81b2},
+ {0x00, 0x27, 0x8191},
+ {0x00, 0x27, 0x81a2},
+ {0x00, 0x27, 0x81b3},
+ {0x00, 0x4b, 0x8192},
+ {0x00, 0x4b, 0x81a3},
+ {0x00, 0x4b, 0x81b4},
+ {0x00, 0x66, 0x8193},
+ {0x00, 0x66, 0x81a4},
+ {0x00, 0x66, 0x81b5},
+ {0x00, 0x79, 0x8194},
+ {0x00, 0x79, 0x81a5},
+ {0x00, 0x79, 0x81b6},
+ {0x00, 0x8a, 0x8195},
+ {0x00, 0x8a, 0x81a6},
+ {0x00, 0x8a, 0x81b7},
+ {0x00, 0x9b, 0x8196},
+ {0x00, 0x9b, 0x81a7},
+ {0x00, 0x9b, 0x81b8},
+ {0x00, 0xa6, 0x8197},
+ {0x00, 0xa6, 0x81a8},
+ {0x00, 0xa6, 0x81b9},
+ {0x00, 0xb2, 0x8198},
+ {0x00, 0xb2, 0x81a9},
+ {0x00, 0xb2, 0x81ba},
+ {0x00, 0xbe, 0x8199},
+ {0x00, 0xbe, 0x81aa},
+ {0x00, 0xbe, 0x81bb},
+ {0x00, 0xc8, 0x819a},
+ {0x00, 0xc8, 0x81ab},
+ {0x00, 0xc8, 0x81bc},
+ {0x00, 0xd2, 0x819b},
+ {0x00, 0xd2, 0x81ac},
+ {0x00, 0xd2, 0x81bd},
+ {0x00, 0xdb, 0x819c},
+ {0x00, 0xdb, 0x81ad},
+ {0x00, 0xdb, 0x81be},
+ {0x00, 0xe4, 0x819d},
+ {0x00, 0xe4, 0x81ae},
+ {0x00, 0xe4, 0x81bf},
+ {0x00, 0xed, 0x819e},
+ {0x00, 0xed, 0x81af},
+ {0x00, 0xed, 0x81c0},
+ {0x00, 0xf7, 0x819f},
+ {0x00, 0xf7, 0x81b0},
+ {0x00, 0xf7, 0x81c1},
+ {0x00, 0xff, 0x81a0},
+ {0x00, 0xff, 0x81b1},
+ {0x00, 0xff, 0x81c2},
+ {0x00, 0x03, 0x8156},
+ {0x00, 0x00, 0x8211},
+ {0x00, 0x20, 0x8168},
+ {0x00, 0x01, 0x8202},
+ {0x00, 0x30, 0x8101},
+ {0x00, 0x00, 0x8111},
+ {0x00, 0x00, 0x8112},
+ {0x00, 0x00, 0x8113},
+ {0x00, 0x00, 0x8114},
+ {}
+};
+
+static const __u8 qtable_creative_pccam[2][64] = {
+ { /* Q-table Y-components */
+ 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+ 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+ 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+ 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+ 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+ 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+ 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+ 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
+ { /* Q-table C-components */
+ 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+static const __u8 qtable_kodak_ez200[2][64] = {
+ { /* Q-table Y-components */
+ 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x06,
+ 0x01, 0x01, 0x01, 0x02, 0x03, 0x06, 0x06, 0x06,
+ 0x01, 0x01, 0x02, 0x02, 0x04, 0x06, 0x07, 0x06,
+ 0x01, 0x02, 0x02, 0x03, 0x05, 0x09, 0x08, 0x06,
+ 0x02, 0x02, 0x04, 0x06, 0x07, 0x0b, 0x0a, 0x08,
+ 0x02, 0x04, 0x06, 0x06, 0x08, 0x0a, 0x0b, 0x09,
+ 0x05, 0x06, 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x0a,
+ 0x07, 0x09, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a},
+ { /* Q-table C-components */
+ 0x02, 0x02, 0x02, 0x05, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x02, 0x02, 0x03, 0x07, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x02, 0x03, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x05, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a}
+};
+
+static const __u8 qtable_pocketdv[2][64] = {
+ { /* Q-table Y-components start registers 0x8800 */
+ 0x06, 0x04, 0x04, 0x06, 0x0a, 0x10, 0x14, 0x18,
+ 0x05, 0x05, 0x06, 0x08, 0x0a, 0x17, 0x18, 0x16,
+ 0x06, 0x05, 0x06, 0x0a, 0x10, 0x17, 0x1c, 0x16,
+ 0x06, 0x07, 0x09, 0x0c, 0x14, 0x23, 0x20, 0x19,
+ 0x07, 0x09, 0x0f, 0x16, 0x1b, 0x2c, 0x29, 0x1f,
+ 0x0a, 0x0e, 0x16, 0x1a, 0x20, 0x2a, 0x2d, 0x25,
+ 0x14, 0x1a, 0x1f, 0x23, 0x29, 0x30, 0x30, 0x28,
+ 0x1d, 0x25, 0x26, 0x27, 0x2d, 0x28, 0x29, 0x28,
+ },
+ { /* Q-table C-components start registers 0x8840 */
+ 0x07, 0x07, 0x0a, 0x13, 0x28, 0x28, 0x28, 0x28,
+ 0x07, 0x08, 0x0a, 0x1a, 0x28, 0x28, 0x28, 0x28,
+ 0x0a, 0x0a, 0x16, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x13, 0x1a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28}
+};
+
+/* read 'len' bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+ __u16 index,
+ __u16 length)
+{
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, length, 500);
+}
+
+static int reg_w(struct gspca_dev *gspca_dev,
+ __u16 req, __u16 index, __u16 value)
+{
+ int ret;
+
+ PDEBUG(D_USBO, "reg write: [0x%02x] = 0x%02x", index, value);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg write: error %d", ret);
+ return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_r_12(struct gspca_dev *gspca_dev,
+ __u16 req, /* bRequest */
+ __u16 index, /* wIndex */
+ __u16 length) /* wLength (1 or 2 only) */
+{
+ int ret;
+
+ gspca_dev->usb_buf[1] = 0;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index,
+ gspca_dev->usb_buf, length,
+ 500); /* timeout */
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_r_12 err %d", ret);
+ return -1;
+ }
+ return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
+}
+
+/*
+ * Simple function to wait for a given 8-bit value to be returned from
+ * a reg_read call.
+ * Returns: negative is error or timeout, zero is success.
+ */
+static int reg_r_wait(struct gspca_dev *gspca_dev,
+ __u16 reg, __u16 index, __u16 value)
+{
+ int ret, cnt = 20;
+
+ while (--cnt > 0) {
+ ret = reg_r_12(gspca_dev, reg, index, 1);
+ if (ret == value)
+ return 0;
+ msleep(50);
+ }
+ return -EIO;
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][3])
+{
+ int ret, i = 0;
+
+ while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+ ret = reg_w(gspca_dev, data[i][0], data[i][2], data[i][1]);
+ if (ret < 0)
+ return ret;
+ i++;
+ }
+ return 0;
+}
+
+static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
+ unsigned int request,
+ unsigned int ybase,
+ unsigned int cbase,
+ const __u8 qtable[2][64])
+{
+ int i, err;
+
+ /* loop over y components */
+ for (i = 0; i < 64; i++) {
+ err = reg_w(gspca_dev, request, ybase + i, qtable[0][i]);
+ if (err < 0)
+ return err;
+ }
+
+ /* loop over c components */
+ for (i = 0; i < 64; i++) {
+ err = reg_w(gspca_dev, request, cbase + i, qtable[1][i]);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static void spca500_ping310(struct gspca_dev *gspca_dev)
+{
+ reg_r(gspca_dev, 0x0d04, 2);
+ PDEBUG(D_STREAM, "ClickSmart310 ping 0x0d04 0x%02x 0x%02x",
+ gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
+}
+
+static void spca500_clksmart310_init(struct gspca_dev *gspca_dev)
+{
+ reg_r(gspca_dev, 0x0d05, 2);
+ PDEBUG(D_STREAM, "ClickSmart310 init 0x0d05 0x%02x 0x%02x",
+ gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
+ reg_w(gspca_dev, 0x00, 0x8167, 0x5a);
+ spca500_ping310(gspca_dev);
+
+ reg_w(gspca_dev, 0x00, 0x8168, 0x22);
+ reg_w(gspca_dev, 0x00, 0x816a, 0xc0);
+ reg_w(gspca_dev, 0x00, 0x816b, 0x0b);
+ reg_w(gspca_dev, 0x00, 0x8169, 0x25);
+ reg_w(gspca_dev, 0x00, 0x8157, 0x5b);
+ reg_w(gspca_dev, 0x00, 0x8158, 0x5b);
+ reg_w(gspca_dev, 0x00, 0x813f, 0x03);
+ reg_w(gspca_dev, 0x00, 0x8151, 0x4a);
+ reg_w(gspca_dev, 0x00, 0x8153, 0x78);
+ reg_w(gspca_dev, 0x00, 0x0d01, 0x04);
+ /* 00 for adjust shutter */
+ reg_w(gspca_dev, 0x00, 0x0d02, 0x01);
+ reg_w(gspca_dev, 0x00, 0x8169, 0x25);
+ reg_w(gspca_dev, 0x00, 0x0d01, 0x02);
+}
+
+static void spca500_setmode(struct gspca_dev *gspca_dev,
+ __u8 xmult, __u8 ymult)
+{
+ int mode;
+
+ /* set x multiplier */
+ reg_w(gspca_dev, 0, 0x8001, xmult);
+
+ /* set y multiplier */
+ reg_w(gspca_dev, 0, 0x8002, ymult);
+
+ /* use compressed mode, VGA, with mode specific subsample */
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ reg_w(gspca_dev, 0, 0x8003, mode << 4);
+}
+
+static int spca500_full_reset(struct gspca_dev *gspca_dev)
+{
+ int err;
+
+ /* send the reset command */
+ err = reg_w(gspca_dev, 0xe0, 0x0001, 0x0000);
+ if (err < 0)
+ return err;
+
+ /* wait for the reset to complete */
+ err = reg_r_wait(gspca_dev, 0x06, 0x0000, 0x0000);
+ if (err < 0)
+ return err;
+ err = reg_w(gspca_dev, 0xe0, 0x0000, 0x0000);
+ if (err < 0)
+ return err;
+ err = reg_r_wait(gspca_dev, 0x06, 0, 0);
+ if (err < 0) {
+ PDEBUG(D_ERR, "reg_r_wait() failed");
+ return err;
+ }
+ /* all ok */
+ return 0;
+}
+
+/* Synchro the Bridge with sensor */
+/* Maybe that will work on all spca500 chip */
+/* because i only own a clicksmart310 try for that chip */
+/* using spca50x_set_packet_size() cause an Ooops here */
+/* usb_set_interface from kernel 2.6.x clear all the urb stuff */
+/* up-port the same feature as in 2.4.x kernel */
+static int spca500_synch310(struct gspca_dev *gspca_dev)
+{
+ if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) {
+ PDEBUG(D_ERR, "Set packet size: set interface error");
+ goto error;
+ }
+ spca500_ping310(gspca_dev);
+
+ reg_r(gspca_dev, 0x0d00, 1);
+
+ /* need alt setting here */
+ PDEBUG(D_PACK, "ClickSmart310 sync alt: %d", gspca_dev->alt);
+
+ /* Windoze use pipe with altsetting 6 why 7 here */
+ if (usb_set_interface(gspca_dev->dev,
+ gspca_dev->iface,
+ gspca_dev->alt) < 0) {
+ PDEBUG(D_ERR, "Set packet size: set interface error");
+ goto error;
+ }
+ return 0;
+error:
+ return -EBUSY;
+}
+
+static void spca500_reinit(struct gspca_dev *gspca_dev)
+{
+ int err;
+ __u8 Data;
+
+ /* some unknow command from Aiptek pocket dv and family300 */
+
+ reg_w(gspca_dev, 0x00, 0x0d01, 0x01);
+ reg_w(gspca_dev, 0x00, 0x0d03, 0x00);
+ reg_w(gspca_dev, 0x00, 0x0d02, 0x01);
+
+ /* enable drop packet */
+ reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+
+ err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840,
+ qtable_pocketdv);
+ if (err < 0)
+ PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed on init");
+
+ /* set qtable index */
+ reg_w(gspca_dev, 0x00, 0x8880, 2);
+ /* family cam Quicksmart stuff */
+ reg_w(gspca_dev, 0x00, 0x800a, 0x00);
+ /* Set agc transfer: synced inbetween frames */
+ reg_w(gspca_dev, 0x00, 0x820f, 0x01);
+ /* Init SDRAM - needed for SDRAM access */
+ reg_w(gspca_dev, 0x00, 0x870a, 0x04);
+ /*Start init sequence or stream */
+ reg_w(gspca_dev, 0, 0x8003, 0x00);
+ /* switch to video camera mode */
+ reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+ msleep(2000);
+ if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) {
+ reg_r(gspca_dev, 0x816b, 1);
+ Data = gspca_dev->usb_buf[0];
+ reg_w(gspca_dev, 0x00, 0x816b, Data);
+ }
+}
+
+/* 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;
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ switch (vendor) {
+ case 0x040a: /* Kodak cameras */
+/* switch (product) { */
+/* case 0x0300: */
+ sd->subtype = KodakEZ200;
+/* break; */
+/* } */
+ break;
+ case 0x041e: /* Creative cameras */
+/* switch (product) { */
+/* case 0x400a: */
+ sd->subtype = CreativePCCam300;
+/* break; */
+/* } */
+ break;
+ case 0x046d: /* Logitech Labtec */
+ switch (product) {
+ case 0x0890:
+ sd->subtype = LogitechTraveler;
+ break;
+ case 0x0900:
+ sd->subtype = LogitechClickSmart310;
+ break;
+ case 0x0901:
+ sd->subtype = LogitechClickSmart510;
+ break;
+ }
+ break;
+ case 0x04a5: /* Benq */
+/* switch (product) { */
+/* case 0x300c: */
+ sd->subtype = BenqDC1016;
+/* break; */
+/* } */
+ break;
+ case 0x04fc: /* SunPlus */
+/* switch (product) { */
+/* case 0x7333: */
+ sd->subtype = PalmPixDC85;
+/* break; */
+/* } */
+ break;
+ case 0x055f: /* Mustek cameras */
+ switch (product) {
+ case 0xc200:
+ sd->subtype = MustekGsmart300;
+ break;
+ case 0xc220:
+ sd->subtype = Gsmartmini;
+ break;
+ }
+ break;
+ case 0x06bd: /* Agfa Cl20 */
+/* switch (product) { */
+/* case 0x0404: */
+ sd->subtype = AgfaCl20;
+/* break; */
+/* } */
+ break;
+ case 0x06be: /* Optimedia */
+/* switch (product) { */
+/* case 0x0800: */
+ sd->subtype = Optimedia;
+/* break; */
+/* } */
+ break;
+ case 0x084d: /* D-Link / Minton */
+/* switch (product) { */
+/* case 0x0003: * DSC-350 / S-Cam F5 */
+ sd->subtype = DLinkDSC350;
+/* break; */
+/* } */
+ break;
+ case 0x08ca: /* Aiptek */
+/* switch (product) { */
+/* case 0x0103: */
+ sd->subtype = AiptekPocketDV;
+/* break; */
+/* } */
+ break;
+ case 0x2899: /* ToptroIndustrial */
+/* switch (product) { */
+/* case 0x012c: */
+ sd->subtype = ToptroIndus;
+/* break; */
+/* } */
+ break;
+ case 0x8086: /* Intel */
+/* switch (product) { */
+/* case 0x0630: * Pocket PC Camera */
+ sd->subtype = IntelPocketPCCamera;
+/* break; */
+/* } */
+ break;
+ }
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ if (sd->subtype != LogitechClickSmart310) {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ } else {
+ cam->cam_mode = sif_mode;
+ cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ }
+ sd->qindex = 5;
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* initialisation of spca500 based cameras is deferred */
+ PDEBUG(D_STREAM, "SPCA500 init");
+ if (sd->subtype == LogitechClickSmart310)
+ spca500_clksmart310_init(gspca_dev);
+/* else
+ spca500_initialise(gspca_dev); */
+ PDEBUG(D_STREAM, "SPCA500 init done");
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int err;
+ __u8 Data;
+ __u8 xmult, ymult;
+
+ if (sd->subtype == LogitechClickSmart310) {
+ xmult = 0x16;
+ ymult = 0x12;
+ } else {
+ xmult = 0x28;
+ ymult = 0x1e;
+ }
+
+ /* is there a sensor here ? */
+ reg_r(gspca_dev, 0x8a04, 1);
+ PDEBUG(D_STREAM, "Spca500 Sensor Address 0x%02x",
+ gspca_dev->usb_buf[0]);
+ PDEBUG(D_STREAM, "Spca500 curr_mode: %d Xmult: 0x%02x, Ymult: 0x%02x",
+ gspca_dev->curr_mode, xmult, ymult);
+
+ /* setup qtable */
+ switch (sd->subtype) {
+ case LogitechClickSmart310:
+ spca500_setmode(gspca_dev, xmult, ymult);
+
+ /* enable drop packet */
+ reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+ reg_w(gspca_dev, 0x00, 0x8880, 3);
+ err = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x8800, 0x8840,
+ qtable_creative_pccam);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ /* Init SDRAM - needed for SDRAM access */
+ reg_w(gspca_dev, 0x00, 0x870a, 0x04);
+
+ /* switch to video camera mode */
+ reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+ msleep(500);
+ if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
+ PDEBUG(D_ERR, "reg_r_wait() failed");
+
+ reg_r(gspca_dev, 0x816b, 1);
+ Data = gspca_dev->usb_buf[0];
+ reg_w(gspca_dev, 0x00, 0x816b, Data);
+
+ spca500_synch310(gspca_dev);
+
+ write_vector(gspca_dev, spca500_visual_defaults);
+ spca500_setmode(gspca_dev, xmult, ymult);
+ /* enable drop packet */
+ reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+ PDEBUG(D_ERR, "failed to enable drop packet");
+ reg_w(gspca_dev, 0x00, 0x8880, 3);
+ err = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x8800, 0x8840,
+ qtable_creative_pccam);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+
+ /* Init SDRAM - needed for SDRAM access */
+ reg_w(gspca_dev, 0x00, 0x870a, 0x04);
+
+ /* switch to video camera mode */
+ reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+
+ if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
+ PDEBUG(D_ERR, "reg_r_wait() failed");
+
+ reg_r(gspca_dev, 0x816b, 1);
+ Data = gspca_dev->usb_buf[0];
+ reg_w(gspca_dev, 0x00, 0x816b, Data);
+ break;
+ case CreativePCCam300: /* Creative PC-CAM 300 640x480 CCD */
+ case IntelPocketPCCamera: /* FIXME: Temporary fix for
+ * Intel Pocket PC Camera
+ * - NWG (Sat 29th March 2003) */
+
+ /* do a full reset */
+ err = spca500_full_reset(gspca_dev);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca500_full_reset failed");
+
+ /* enable drop packet */
+ err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+ if (err < 0)
+ PDEBUG(D_ERR, "failed to enable drop packet");
+ reg_w(gspca_dev, 0x00, 0x8880, 3);
+ err = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x8800, 0x8840,
+ qtable_creative_pccam);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+
+ spca500_setmode(gspca_dev, xmult, ymult);
+ reg_w(gspca_dev, 0x20, 0x0001, 0x0004);
+
+ /* switch to video camera mode */
+ reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+
+ if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
+ PDEBUG(D_ERR, "reg_r_wait() failed");
+
+ reg_r(gspca_dev, 0x816b, 1);
+ Data = gspca_dev->usb_buf[0];
+ reg_w(gspca_dev, 0x00, 0x816b, Data);
+
+/* write_vector(gspca_dev, spca500_visual_defaults); */
+ break;
+ case KodakEZ200: /* Kodak EZ200 */
+
+ /* do a full reset */
+ err = spca500_full_reset(gspca_dev);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca500_full_reset failed");
+ /* enable drop packet */
+ reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+ reg_w(gspca_dev, 0x00, 0x8880, 0);
+ err = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x8800, 0x8840,
+ qtable_kodak_ez200);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ spca500_setmode(gspca_dev, xmult, ymult);
+
+ reg_w(gspca_dev, 0x20, 0x0001, 0x0004);
+
+ /* switch to video camera mode */
+ reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+
+ if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
+ PDEBUG(D_ERR, "reg_r_wait() failed");
+
+ reg_r(gspca_dev, 0x816b, 1);
+ Data = gspca_dev->usb_buf[0];
+ reg_w(gspca_dev, 0x00, 0x816b, Data);
+
+/* write_vector(gspca_dev, spca500_visual_defaults); */
+ break;
+
+ case BenqDC1016:
+ case DLinkDSC350: /* FamilyCam 300 */
+ case AiptekPocketDV: /* Aiptek PocketDV */
+ case Gsmartmini: /*Mustek Gsmart Mini */
+ case MustekGsmart300: /* Mustek Gsmart 300 */
+ case PalmPixDC85:
+ case Optimedia:
+ case ToptroIndus:
+ case AgfaCl20:
+ spca500_reinit(gspca_dev);
+ reg_w(gspca_dev, 0x00, 0x0d01, 0x01);
+ /* enable drop packet */
+ reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+
+ err = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x8800, 0x8840, qtable_pocketdv);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ reg_w(gspca_dev, 0x00, 0x8880, 2);
+
+ /* familycam Quicksmart pocketDV stuff */
+ reg_w(gspca_dev, 0x00, 0x800a, 0x00);
+ /* Set agc transfer: synced inbetween frames */
+ reg_w(gspca_dev, 0x00, 0x820f, 0x01);
+ /* Init SDRAM - needed for SDRAM access */
+ reg_w(gspca_dev, 0x00, 0x870a, 0x04);
+
+ spca500_setmode(gspca_dev, xmult, ymult);
+ /* switch to video camera mode */
+ reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+
+ reg_r_wait(gspca_dev, 0, 0x8000, 0x44);
+
+ reg_r(gspca_dev, 0x816b, 1);
+ Data = gspca_dev->usb_buf[0];
+ reg_w(gspca_dev, 0x00, 0x816b, Data);
+ break;
+ case LogitechTraveler:
+ case LogitechClickSmart510:
+ reg_w(gspca_dev, 0x02, 0x00, 0x00);
+ /* enable drop packet */
+ reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+
+ err = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x8800,
+ 0x8840, qtable_creative_pccam);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ reg_w(gspca_dev, 0x00, 0x8880, 3);
+ reg_w(gspca_dev, 0x00, 0x800a, 0x00);
+ /* Init SDRAM - needed for SDRAM access */
+ reg_w(gspca_dev, 0x00, 0x870a, 0x04);
+
+ spca500_setmode(gspca_dev, xmult, ymult);
+
+ /* switch to video camera mode */
+ reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+ reg_r_wait(gspca_dev, 0, 0x8000, 0x44);
+
+ reg_r(gspca_dev, 0x816b, 1);
+ Data = gspca_dev->usb_buf[0];
+ reg_w(gspca_dev, 0x00, 0x816b, Data);
+ write_vector(gspca_dev, Clicksmart510_defaults);
+ break;
+ }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, 0, 0x8003, 0x00);
+
+ /* switch to video camera mode */
+ reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+ reg_r(gspca_dev, 0x8000, 1);
+ PDEBUG(D_STREAM, "stop SPCA500 done reg8000: 0x%2x",
+ gspca_dev->usb_buf[0]);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+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;
+ int i;
+ __u8 *s, *d;
+ static __u8 ffd9[] = {0xff, 0xd9};
+
+/* frames are jpeg 4.1.1 without 0xff escape */
+ if (data[0] == 0xff) {
+ if (data[1] != 0x01) { /* drop packet */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ ffd9, 2);
+
+ /* put the JPEG header in the new frame */
+ jpeg_put_header(gspca_dev, frame, sd->qindex, 0x22);
+
+ data += SPCA500_OFFSET_DATA;
+ len -= SPCA500_OFFSET_DATA;
+ } else {
+ data += 1;
+ len -= 1;
+ }
+
+ /* add 0x00 after 0xff */
+ for (i = len; --i >= 0; )
+ if (data[i] == 0xff)
+ break;
+ if (i < 0) { /* no 0xff */
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+ return;
+ }
+ s = data;
+ d = sd->packet;
+ for (i = 0; i < len; i++) {
+ *d++ = *s++;
+ if (s[-1] == 0xff)
+ *d++ = 0x00;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ sd->packet, d - sd->packet);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w(gspca_dev, 0x00, 0x8167,
+ (__u8) (sd->brightness - 128));
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ ret = reg_r_12(gspca_dev, 0x00, 0x8167, 1);
+ if (ret >= 0)
+ sd->brightness = ret + 128;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w(gspca_dev, 0x00, 0x8168, sd->contrast);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ ret = reg_r_12(gspca_dev, 0x0, 0x8168, 1);
+ if (ret >= 0)
+ sd->contrast = ret;
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w(gspca_dev, 0x00, 0x8169, sd->colors);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ ret = reg_r_12(gspca_dev, 0x0, 0x8169, 1);
+ if (ret >= 0)
+ sd->colors = ret;
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x040a, 0x0300), DVNM("Kodak EZ200")},
+ {USB_DEVICE(0x041e, 0x400a), DVNM("Creative PC-CAM 300")},
+ {USB_DEVICE(0x046d, 0x0890), DVNM("Logitech QuickCam traveler")},
+ {USB_DEVICE(0x046d, 0x0900), DVNM("Logitech Inc. ClickSmart 310")},
+ {USB_DEVICE(0x046d, 0x0901), DVNM("Logitech Inc. ClickSmart 510")},
+ {USB_DEVICE(0x04a5, 0x300c), DVNM("Benq DC1016")},
+ {USB_DEVICE(0x04fc, 0x7333), DVNM("PalmPixDC85")},
+ {USB_DEVICE(0x055f, 0xc200), DVNM("Mustek Gsmart 300")},
+ {USB_DEVICE(0x055f, 0xc220), DVNM("Gsmart Mini")},
+ {USB_DEVICE(0x06bd, 0x0404), DVNM("Agfa CL20")},
+ {USB_DEVICE(0x06be, 0x0800), DVNM("Optimedia")},
+ {USB_DEVICE(0x084d, 0x0003), DVNM("D-Link DSC-350")},
+ {USB_DEVICE(0x08ca, 0x0103), DVNM("Aiptek PocketDV")},
+ {USB_DEVICE(0x2899, 0x012c), DVNM("Toptro Industrial")},
+ {USB_DEVICE(0x8086, 0x0630), DVNM("Intel Pocket PC Camera")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
new file mode 100644
index 00000000000..50e929de020
--- /dev/null
+++ b/drivers/media/video/gspca/spca501.c
@@ -0,0 +1,2229 @@
+/*
+ * SPCA501 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "spca501"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA501 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned short contrast;
+ __u8 brightness;
+ __u8 colors;
+
+ char subtype;
+#define Arowana300KCMOSCamera 0
+#define IntelCreateAndShare 1
+#define KodakDVC325 2
+#define MystFromOriUnknownCamera 3
+#define SmileIntlCamera 4
+#define ThreeComHomeConnectLite 5
+#define ViewQuestM318B 6
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define MY_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 63,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define MY_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0xffff,
+ .step = 1,
+ .default_value = 0xaa00,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define MY_COLOR 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ .default_value = 31,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+#define SPCA50X_REG_USB 0x2 /* spca505 501 */
+/*
+ * Data to initialize a SPCA501. From a capture file provided by Bill Roehl
+ * With SPCA501 chip description
+ */
+#define CCDSP_SET /* set CCDSP parameters */
+#define TG_SET /* set time generator set */
+#undef DSPWIN_SET /* set DSP windows parameters */
+#undef ALTER_GAMA /* Set alternate set to YUV transform coeffs. */
+#define SPCA501_SNAPBIT 0x80
+#define SPCA501_SNAPCTRL 0x10
+/* Frame packet header offsets for the spca501 */
+#define SPCA501_OFFSET_GPIO 1
+#define SPCA501_OFFSET_TYPE 2
+#define SPCA501_OFFSET_TURN3A 3
+#define SPCA501_OFFSET_FRAMSEQ 4
+#define SPCA501_OFFSET_COMPRESS 5
+#define SPCA501_OFFSET_QUANT 6
+#define SPCA501_OFFSET_QUANT2 7
+#define SPCA501_OFFSET_DATA 8
+
+#define SPCA501_PROP_COMP_ENABLE(d) ((d) & 1)
+#define SPCA501_PROP_SNAP(d) ((d) & 0x40)
+#define SPCA501_PROP_SNAP_CTRL(d) ((d) & 0x10)
+#define SPCA501_PROP_COMP_THRESH(d) (((d) & 0x0e) >> 1)
+#define SPCA501_PROP_COMP_QUANT(d) (((d) & 0x70) >> 4)
+
+/* SPCA501 CCDSP control */
+#define SPCA501_REG_CCDSP 0x01
+/* SPCA501 control/status registers */
+#define SPCA501_REG_CTLRL 0x02
+
+/* registers for color correction and YUV transformation */
+#define SPCA501_A11 0x08
+#define SPCA501_A12 0x09
+#define SPCA501_A13 0x0A
+#define SPCA501_A21 0x0B
+#define SPCA501_A22 0x0C
+#define SPCA501_A23 0x0D
+#define SPCA501_A31 0x0E
+#define SPCA501_A32 0x0F
+#define SPCA501_A33 0x10
+
+/* Data for video camera initialization before capturing */
+static const __u16 spca501_open_data[][3] = {
+ /* bmRequest,value,index */
+
+ {0x2, 0x50, 0x00}, /* C/S enable soft reset */
+ {0x2, 0x40, 0x00}, /* C/S disable soft reset */
+ {0x2, 0x02, 0x05}, /* C/S general purpose I/O data */
+ {0x2, 0x03, 0x05}, /* C/S general purpose I/O data */
+
+#ifdef CCDSP_SET
+ {0x1, 0x38, 0x01}, /* CCDSP options */
+ {0x1, 0x05, 0x02}, /* CCDSP Optical black level for user settings */
+ {0x1, 0xC0, 0x03}, /* CCDSP Optical black settings */
+
+ {0x1, 0x67, 0x07},
+ {0x1, 0x63, 0x3f}, /* CCDSP CCD gamma enable */
+ {0x1, 0x03, 0x56}, /* Add gamma correction */
+
+ {0x1, 0xFF, 0x15}, /* CCDSP High luminance for white balance */
+ {0x1, 0x01, 0x16}, /* CCDSP Low luminance for white balance */
+
+/* Color correction and RGB-to-YUV transformation coefficients changing */
+#ifdef ALTER_GAMA
+ {0x0, 0x00, 0x08}, /* A11 */
+ {0x0, 0x00, 0x09}, /* A12 */
+ {0x0, 0x90, 0x0A}, /* A13 */
+ {0x0, 0x12, 0x0B}, /* A21 */
+ {0x0, 0x00, 0x0C}, /* A22 */
+ {0x0, 0x00, 0x0D}, /* A23 */
+ {0x0, 0x00, 0x0E}, /* A31 */
+ {0x0, 0x02, 0x0F}, /* A32 */
+ {0x0, 0x00, 0x10}, /* A33 */
+#else
+ {0x1, 0x2a, 0x08}, /* A11 0x31 */
+ {0x1, 0xf8, 0x09}, /* A12 f8 */
+ {0x1, 0xf8, 0x0A}, /* A13 f8 */
+ {0x1, 0xf8, 0x0B}, /* A21 f8 */
+ {0x1, 0x14, 0x0C}, /* A22 0x14 */
+ {0x1, 0xf8, 0x0D}, /* A23 f8 */
+ {0x1, 0xf8, 0x0E}, /* A31 f8 */
+ {0x1, 0xf8, 0x0F}, /* A32 f8 */
+ {0x1, 0x20, 0x10}, /* A33 0x20 */
+#endif
+ {0x1, 0x00, 0x11}, /* R offset */
+ {0x1, 0x00, 0x12}, /* G offset */
+ {0x1, 0x00, 0x13}, /* B offset */
+ {0x1, 0x00, 0x14}, /* GB offset */
+
+#endif
+
+#ifdef TG_SET
+ /* Time generator manipulations */
+ {0x0, 0xfc, 0x0}, /* Set up high bits of shutter speed */
+ {0x0, 0x01, 0x1}, /* Set up low bits of shutter speed */
+
+ {0x0, 0xe4, 0x04}, /* DCLK*2 clock phase adjustment */
+ {0x0, 0x08, 0x05}, /* ADCK phase adjustment, inv. ext. VB */
+ {0x0, 0x03, 0x06}, /* FR phase adjustment */
+ {0x0, 0x01, 0x07}, /* FCDS phase adjustment */
+ {0x0, 0x39, 0x08}, /* FS phase adjustment */
+ {0x0, 0x88, 0x0a}, /* FH1 phase and delay adjustment */
+ {0x0, 0x03, 0x0f}, /* pixel identification */
+ {0x0, 0x00, 0x11}, /* clock source selection (default) */
+
+ /*VERY strange manipulations with
+ * select DMCLP or OBPX to be ADCLP output (0x0C)
+ * OPB always toggle or not (0x0D) but they allow
+ * us to set up brightness
+ */
+ {0x0, 0x01, 0x0c},
+ {0x0, 0xe0, 0x0d},
+ /* Done */
+#endif
+
+#ifdef DSPWIN_SET
+ {0x1, 0xa0, 0x01}, /* Setting image processing parameters */
+ {0x1, 0x1c, 0x17}, /* Changing Windows positions X1 */
+ {0x1, 0xe2, 0x19}, /* X2 */
+ {0x1, 0x1c, 0x1b}, /* X3 */
+ {0x1, 0xe2, 0x1d}, /* X4 */
+ {0x1, 0x5f, 0x1f}, /* X5 */
+ {0x1, 0x32, 0x20}, /* Y5 */
+ {0x1, 0x01, 0x10}, /* Changing A33 */
+#endif
+
+ {0x2, 0x204a, 0x07},/* Setting video compression & resolution 160x120 */
+ {0x2, 0x94, 0x06}, /* Setting video no compression */
+ {}
+};
+
+/*
+ The SPCAxxx docs from Sunplus document these values
+ in tables, one table per register number. In the data
+ below, dmRequest is the register number, index is the Addr,
+ and value is a combination of Bit values.
+ Bit Value (hex)
+ 0 01
+ 1 02
+ 2 04
+ 3 08
+ 4 10
+ 5 20
+ 6 40
+ 7 80
+ */
+
+/* Data for chip initialization (set default values) */
+static const __u16 spca501_init_data[][3] = {
+ /* Set all the values to powerup defaults */
+ /* bmRequest,value,index */
+ {0x0, 0xAA, 0x00},
+ {0x0, 0x02, 0x01},
+ {0x0, 0x01, 0x02},
+ {0x0, 0x02, 0x03},
+ {0x0, 0xCE, 0x04},
+ {0x0, 0x00, 0x05},
+ {0x0, 0x00, 0x06},
+ {0x0, 0x00, 0x07},
+ {0x0, 0x00, 0x08},
+ {0x0, 0x00, 0x09},
+ {0x0, 0x90, 0x0A},
+ {0x0, 0x12, 0x0B},
+ {0x0, 0x00, 0x0C},
+ {0x0, 0x00, 0x0D},
+ {0x0, 0x00, 0x0E},
+ {0x0, 0x02, 0x0F},
+ {0x0, 0x00, 0x10},
+ {0x0, 0x00, 0x11},
+ {0x0, 0x00, 0x12},
+ {0x0, 0x00, 0x13},
+ {0x0, 0x00, 0x14},
+ {0x0, 0x00, 0x15},
+ {0x0, 0x00, 0x16},
+ {0x0, 0x00, 0x17},
+ {0x0, 0x00, 0x18},
+ {0x0, 0x00, 0x19},
+ {0x0, 0x00, 0x1A},
+ {0x0, 0x00, 0x1B},
+ {0x0, 0x00, 0x1C},
+ {0x0, 0x00, 0x1D},
+ {0x0, 0x00, 0x1E},
+ {0x0, 0x00, 0x1F},
+ {0x0, 0x00, 0x20},
+ {0x0, 0x00, 0x21},
+ {0x0, 0x00, 0x22},
+ {0x0, 0x00, 0x23},
+ {0x0, 0x00, 0x24},
+ {0x0, 0x00, 0x25},
+ {0x0, 0x00, 0x26},
+ {0x0, 0x00, 0x27},
+ {0x0, 0x00, 0x28},
+ {0x0, 0x00, 0x29},
+ {0x0, 0x00, 0x2A},
+ {0x0, 0x00, 0x2B},
+ {0x0, 0x00, 0x2C},
+ {0x0, 0x00, 0x2D},
+ {0x0, 0x00, 0x2E},
+ {0x0, 0x00, 0x2F},
+ {0x0, 0x00, 0x30},
+ {0x0, 0x00, 0x31},
+ {0x0, 0x00, 0x32},
+ {0x0, 0x00, 0x33},
+ {0x0, 0x00, 0x34},
+ {0x0, 0x00, 0x35},
+ {0x0, 0x00, 0x36},
+ {0x0, 0x00, 0x37},
+ {0x0, 0x00, 0x38},
+ {0x0, 0x00, 0x39},
+ {0x0, 0x00, 0x3A},
+ {0x0, 0x00, 0x3B},
+ {0x0, 0x00, 0x3C},
+ {0x0, 0x00, 0x3D},
+ {0x0, 0x00, 0x3E},
+ {0x0, 0x00, 0x3F},
+ {0x0, 0x00, 0x40},
+ {0x0, 0x00, 0x41},
+ {0x0, 0x00, 0x42},
+ {0x0, 0x00, 0x43},
+ {0x0, 0x00, 0x44},
+ {0x0, 0x00, 0x45},
+ {0x0, 0x00, 0x46},
+ {0x0, 0x00, 0x47},
+ {0x0, 0x00, 0x48},
+ {0x0, 0x00, 0x49},
+ {0x0, 0x00, 0x4A},
+ {0x0, 0x00, 0x4B},
+ {0x0, 0x00, 0x4C},
+ {0x0, 0x00, 0x4D},
+ {0x0, 0x00, 0x4E},
+ {0x0, 0x00, 0x4F},
+ {0x0, 0x00, 0x50},
+ {0x0, 0x00, 0x51},
+ {0x0, 0x00, 0x52},
+ {0x0, 0x00, 0x53},
+ {0x0, 0x00, 0x54},
+ {0x0, 0x00, 0x55},
+ {0x0, 0x00, 0x56},
+ {0x0, 0x00, 0x57},
+ {0x0, 0x00, 0x58},
+ {0x0, 0x00, 0x59},
+ {0x0, 0x00, 0x5A},
+ {0x0, 0x00, 0x5B},
+ {0x0, 0x00, 0x5C},
+ {0x0, 0x00, 0x5D},
+ {0x0, 0x00, 0x5E},
+ {0x0, 0x00, 0x5F},
+ {0x0, 0x00, 0x60},
+ {0x0, 0x00, 0x61},
+ {0x0, 0x00, 0x62},
+ {0x0, 0x00, 0x63},
+ {0x0, 0x00, 0x64},
+ {0x0, 0x00, 0x65},
+ {0x0, 0x00, 0x66},
+ {0x0, 0x00, 0x67},
+ {0x0, 0x00, 0x68},
+ {0x0, 0x00, 0x69},
+ {0x0, 0x00, 0x6A},
+ {0x0, 0x00, 0x6B},
+ {0x0, 0x00, 0x6C},
+ {0x0, 0x00, 0x6D},
+ {0x0, 0x00, 0x6E},
+ {0x0, 0x00, 0x6F},
+ {0x0, 0x00, 0x70},
+ {0x0, 0x00, 0x71},
+ {0x0, 0x00, 0x72},
+ {0x0, 0x00, 0x73},
+ {0x0, 0x00, 0x74},
+ {0x0, 0x00, 0x75},
+ {0x0, 0x00, 0x76},
+ {0x0, 0x00, 0x77},
+ {0x0, 0x00, 0x78},
+ {0x0, 0x00, 0x79},
+ {0x0, 0x00, 0x7A},
+ {0x0, 0x00, 0x7B},
+ {0x0, 0x00, 0x7C},
+ {0x0, 0x00, 0x7D},
+ {0x0, 0x00, 0x7E},
+ {0x0, 0x00, 0x7F},
+ {0x0, 0x00, 0x80},
+ {0x0, 0x00, 0x81},
+ {0x0, 0x00, 0x82},
+ {0x0, 0x00, 0x83},
+ {0x0, 0x00, 0x84},
+ {0x0, 0x00, 0x85},
+ {0x0, 0x00, 0x86},
+ {0x0, 0x00, 0x87},
+ {0x0, 0x00, 0x88},
+ {0x0, 0x00, 0x89},
+ {0x0, 0x00, 0x8A},
+ {0x0, 0x00, 0x8B},
+ {0x0, 0x00, 0x8C},
+ {0x0, 0x00, 0x8D},
+ {0x0, 0x00, 0x8E},
+ {0x0, 0x00, 0x8F},
+ {0x0, 0x00, 0x90},
+ {0x0, 0x00, 0x91},
+ {0x0, 0x00, 0x92},
+ {0x0, 0x00, 0x93},
+ {0x0, 0x00, 0x94},
+ {0x0, 0x00, 0x95},
+ {0x0, 0x00, 0x96},
+ {0x0, 0x00, 0x97},
+ {0x0, 0x00, 0x98},
+ {0x0, 0x00, 0x99},
+ {0x0, 0x00, 0x9A},
+ {0x0, 0x00, 0x9B},
+ {0x0, 0x00, 0x9C},
+ {0x0, 0x00, 0x9D},
+ {0x0, 0x00, 0x9E},
+ {0x0, 0x00, 0x9F},
+ {0x0, 0x00, 0xA0},
+ {0x0, 0x00, 0xA1},
+ {0x0, 0x00, 0xA2},
+ {0x0, 0x00, 0xA3},
+ {0x0, 0x00, 0xA4},
+ {0x0, 0x00, 0xA5},
+ {0x0, 0x00, 0xA6},
+ {0x0, 0x00, 0xA7},
+ {0x0, 0x00, 0xA8},
+ {0x0, 0x00, 0xA9},
+ {0x0, 0x00, 0xAA},
+ {0x0, 0x00, 0xAB},
+ {0x0, 0x00, 0xAC},
+ {0x0, 0x00, 0xAD},
+ {0x0, 0x00, 0xAE},
+ {0x0, 0x00, 0xAF},
+ {0x0, 0x00, 0xB0},
+ {0x0, 0x00, 0xB1},
+ {0x0, 0x00, 0xB2},
+ {0x0, 0x00, 0xB3},
+ {0x0, 0x00, 0xB4},
+ {0x0, 0x00, 0xB5},
+ {0x0, 0x00, 0xB6},
+ {0x0, 0x00, 0xB7},
+ {0x0, 0x00, 0xB8},
+ {0x0, 0x00, 0xB9},
+ {0x0, 0x00, 0xBA},
+ {0x0, 0x00, 0xBB},
+ {0x0, 0x00, 0xBC},
+ {0x0, 0x00, 0xBD},
+ {0x0, 0x00, 0xBE},
+ {0x0, 0x00, 0xBF},
+ {0x0, 0x00, 0xC0},
+ {0x0, 0x00, 0xC1},
+ {0x0, 0x00, 0xC2},
+ {0x0, 0x00, 0xC3},
+ {0x0, 0x00, 0xC4},
+ {0x0, 0x00, 0xC5},
+ {0x0, 0x00, 0xC6},
+ {0x0, 0x00, 0xC7},
+ {0x0, 0x00, 0xC8},
+ {0x0, 0x00, 0xC9},
+ {0x0, 0x00, 0xCA},
+ {0x0, 0x00, 0xCB},
+ {0x0, 0x00, 0xCC},
+ {0x1, 0xF4, 0x00},
+ {0x1, 0x38, 0x01},
+ {0x1, 0x40, 0x02},
+ {0x1, 0x0A, 0x03},
+ {0x1, 0x40, 0x04},
+ {0x1, 0x40, 0x05},
+ {0x1, 0x40, 0x06},
+ {0x1, 0x67, 0x07},
+ {0x1, 0x31, 0x08},
+ {0x1, 0x00, 0x09},
+ {0x1, 0x00, 0x0A},
+ {0x1, 0x00, 0x0B},
+ {0x1, 0x14, 0x0C},
+ {0x1, 0x00, 0x0D},
+ {0x1, 0x00, 0x0E},
+ {0x1, 0x00, 0x0F},
+ {0x1, 0x1E, 0x10},
+ {0x1, 0x00, 0x11},
+ {0x1, 0x00, 0x12},
+ {0x1, 0x00, 0x13},
+ {0x1, 0x00, 0x14},
+ {0x1, 0xFF, 0x15},
+ {0x1, 0x01, 0x16},
+ {0x1, 0x32, 0x17},
+ {0x1, 0x23, 0x18},
+ {0x1, 0xCE, 0x19},
+ {0x1, 0x23, 0x1A},
+ {0x1, 0x32, 0x1B},
+ {0x1, 0x8D, 0x1C},
+ {0x1, 0xCE, 0x1D},
+ {0x1, 0x8D, 0x1E},
+ {0x1, 0x00, 0x1F},
+ {0x1, 0x00, 0x20},
+ {0x1, 0xFF, 0x3E},
+ {0x1, 0x02, 0x3F},
+ {0x1, 0x00, 0x40},
+ {0x1, 0x00, 0x41},
+ {0x1, 0x00, 0x42},
+ {0x1, 0x00, 0x43},
+ {0x1, 0x00, 0x44},
+ {0x1, 0x00, 0x45},
+ {0x1, 0x00, 0x46},
+ {0x1, 0x00, 0x47},
+ {0x1, 0x00, 0x48},
+ {0x1, 0x00, 0x49},
+ {0x1, 0x00, 0x4A},
+ {0x1, 0x00, 0x4B},
+ {0x1, 0x00, 0x4C},
+ {0x1, 0x00, 0x4D},
+ {0x1, 0x00, 0x4E},
+ {0x1, 0x00, 0x4F},
+ {0x1, 0x00, 0x50},
+ {0x1, 0x00, 0x51},
+ {0x1, 0x00, 0x52},
+ {0x1, 0x00, 0x53},
+ {0x1, 0x00, 0x54},
+ {0x1, 0x00, 0x55},
+ {0x1, 0x00, 0x56},
+ {0x1, 0x00, 0x57},
+ {0x1, 0x00, 0x58},
+ {0x1, 0x00, 0x59},
+ {0x1, 0x00, 0x5A},
+ {0x2, 0x03, 0x00},
+ {0x2, 0x00, 0x01},
+ {0x2, 0x00, 0x05},
+ {0x2, 0x00, 0x06},
+ {0x2, 0x00, 0x07},
+ {0x2, 0x00, 0x10},
+ {0x2, 0x00, 0x11},
+ /* Strange - looks like the 501 driver doesn't do anything
+ * at insert time except read the EEPROM
+ */
+ {}
+};
+
+/* Data for video camera init before capture.
+ * Capture and decoding by Colin Peart.
+ * This is is for the 3com HomeConnect Lite which is spca501a based.
+ */
+static const __u16 spca501_3com_open_data[][3] = {
+ /* bmRequest,value,index */
+ {0x2, 0x0050, 0x0000}, /* C/S Enable TG soft reset, timing mode=010 */
+ {0x2, 0x0043, 0x0000}, /* C/S Disable TG soft reset, timing mode=010 */
+ {0x2, 0x0002, 0x0005}, /* C/S GPIO */
+ {0x2, 0x0003, 0x0005}, /* C/S GPIO */
+
+#ifdef CCDSP_SET
+ {0x1, 0x0020, 0x0001}, /* CCDSP Options */
+
+ {0x1, 0x0020, 0x0002}, /* CCDSP Black Level */
+ {0x1, 0x006e, 0x0007}, /* CCDSP Gamma options */
+ {0x1, 0x0090, 0x0015}, /* CCDSP Luminance Low */
+ {0x1, 0x00ff, 0x0016}, /* CCDSP Luminance High */
+ {0x1, 0x0003, 0x003F}, /* CCDSP Gamma correction toggle */
+
+#ifdef ALTER_GAMMA
+ {0x1, 0x0010, 0x0008}, /* CCDSP YUV A11 */
+ {0x1, 0x0000, 0x0009}, /* CCDSP YUV A12 */
+ {0x1, 0x0000, 0x000a}, /* CCDSP YUV A13 */
+ {0x1, 0x0000, 0x000b}, /* CCDSP YUV A21 */
+ {0x1, 0x0010, 0x000c}, /* CCDSP YUV A22 */
+ {0x1, 0x0000, 0x000d}, /* CCDSP YUV A23 */
+ {0x1, 0x0000, 0x000e}, /* CCDSP YUV A31 */
+ {0x1, 0x0000, 0x000f}, /* CCDSP YUV A32 */
+ {0x1, 0x0010, 0x0010}, /* CCDSP YUV A33 */
+ {0x1, 0x0000, 0x0011}, /* CCDSP R Offset */
+ {0x1, 0x0000, 0x0012}, /* CCDSP G Offset */
+ {0x1, 0x0001, 0x0013}, /* CCDSP B Offset */
+ {0x1, 0x0001, 0x0014}, /* CCDSP BG Offset */
+ {0x1, 0x003f, 0x00C1}, /* CCDSP Gamma Correction Enable */
+#endif
+#endif
+
+#ifdef TG_SET
+ {0x0, 0x00fc, 0x0000}, /* TG Shutter Speed High Bits */
+ {0x0, 0x0000, 0x0001}, /* TG Shutter Speed Low Bits */
+ {0x0, 0x00e4, 0x0004}, /* TG DCLK*2 Adjust */
+ {0x0, 0x0008, 0x0005}, /* TG ADCK Adjust */
+ {0x0, 0x0003, 0x0006}, /* TG FR Phase Adjust */
+ {0x0, 0x0001, 0x0007}, /* TG FCDS Phase Adjust */
+ {0x0, 0x0039, 0x0008}, /* TG FS Phase Adjust */
+ {0x0, 0x0088, 0x000a}, /* TG MH1 */
+ {0x0, 0x0003, 0x000f}, /* TG Pixel ID */
+
+ /* Like below, unexplained toglleing */
+ {0x0, 0x0080, 0x000c},
+ {0x0, 0x0000, 0x000d},
+ {0x0, 0x0080, 0x000c},
+ {0x0, 0x0004, 0x000d},
+ {0x0, 0x0000, 0x000c},
+ {0x0, 0x0000, 0x000d},
+ {0x0, 0x0040, 0x000c},
+ {0x0, 0x0017, 0x000d},
+ {0x0, 0x00c0, 0x000c},
+ {0x0, 0x0000, 0x000d},
+ {0x0, 0x0080, 0x000c},
+ {0x0, 0x0006, 0x000d},
+ {0x0, 0x0080, 0x000c},
+ {0x0, 0x0004, 0x000d},
+ {0x0, 0x0002, 0x0003},
+#endif
+
+#ifdef DSPWIN_SET
+ {0x1, 0x001c, 0x0017}, /* CCDSP W1 Start X */
+ {0x1, 0x00e2, 0x0019}, /* CCDSP W2 Start X */
+ {0x1, 0x001c, 0x001b}, /* CCDSP W3 Start X */
+ {0x1, 0x00e2, 0x001d}, /* CCDSP W4 Start X */
+ {0x1, 0x00aa, 0x001f}, /* CCDSP W5 Start X */
+ {0x1, 0x0070, 0x0020}, /* CCDSP W5 Start Y */
+#endif
+ {0x0, 0x0001, 0x0010}, /* TG Start Clock */
+
+/* {0x2, 0x006a, 0x0001}, * C/S Enable ISOSYNCH Packet Engine */
+ {0x2, 0x0068, 0x0001}, /* C/S Diable ISOSYNCH Packet Engine */
+ {0x2, 0x0000, 0x0005},
+ {0x2, 0x0043, 0x0000}, /* C/S Set Timing Mode, Disable TG soft reset */
+ {0x2, 0x0043, 0x0000}, /* C/S Set Timing Mode, Disable TG soft reset */
+ {0x2, 0x0002, 0x0005}, /* C/S GPIO */
+ {0x2, 0x0003, 0x0005}, /* C/S GPIO */
+
+ {0x2, 0x006a, 0x0001}, /* C/S Enable ISOSYNCH Packet Engine */
+ {}
+};
+
+/*
+ * Data used to initialize a SPCA501C with HV7131B sensor.
+ * From a capture file taken with USBSnoop v 1.5
+ * I have a "SPCA501C pc camera chipset" manual by sunplus, but some
+ * of the value meanings are obscure or simply "reserved".
+ * to do list:
+ * 1) Understand what every value means
+ * 2) Understand why some values seem to appear more than once
+ * 3) Write a small comment for each line of the following arrays.
+ */
+static const __u16 spca501c_arowana_open_data[][3] = {
+ /* bmRequest,value,index */
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x01, 0x0006, 0x0011},
+ {0x01, 0x00ff, 0x0012},
+ {0x01, 0x0014, 0x0013},
+ {0x01, 0x0000, 0x0014},
+ {0x01, 0x0042, 0x0051},
+ {0x01, 0x0040, 0x0052},
+ {0x01, 0x0051, 0x0053},
+ {0x01, 0x0040, 0x0054},
+ {0x01, 0x0000, 0x0055},
+ {0x00, 0x0025, 0x0000},
+ {0x00, 0x0026, 0x0000},
+ {0x00, 0x0001, 0x0000},
+ {0x00, 0x0027, 0x0000},
+ {0x00, 0x008a, 0x0000},
+ {}
+};
+
+static const __u16 spca501c_arowana_init_data[][3] = {
+ /* bmRequest,value,index */
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x01, 0x0006, 0x0011},
+ {0x01, 0x00ff, 0x0012},
+ {0x01, 0x0014, 0x0013},
+ {0x01, 0x0000, 0x0014},
+ {0x01, 0x0042, 0x0051},
+ {0x01, 0x0040, 0x0052},
+ {0x01, 0x0051, 0x0053},
+ {0x01, 0x0040, 0x0054},
+ {0x01, 0x0000, 0x0055},
+ {0x00, 0x0025, 0x0000},
+ {0x00, 0x0026, 0x0000},
+ {0x00, 0x0001, 0x0000},
+ {0x00, 0x0027, 0x0000},
+ {0x00, 0x008a, 0x0000},
+ {0x02, 0x0000, 0x0005},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x000c, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0000, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021},
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023},
+ {0x00, 0x0000, 0x0024},
+ {0x00, 0x00d5, 0x0025},
+ {0x00, 0x0000, 0x0026},
+ {0x00, 0x000b, 0x0027},
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+ {0xff, 0x0000, 0x00d0},
+ {0xff, 0x00d8, 0x00d1},
+ {0xff, 0x0000, 0x00d4},
+ {0xff, 0x0000, 0x00d5},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003},
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0x00fd, 0x000a},
+ {0x01, 0x0038, 0x000b},
+ {0x01, 0x00d1, 0x000c},
+ {0x01, 0x00f7, 0x000d},
+ {0x01, 0x00ed, 0x000e},
+ {0x01, 0x00d8, 0x000f},
+ {0x01, 0x0038, 0x0010},
+ {0x01, 0x00ff, 0x0015},
+ {0x01, 0x0001, 0x0016},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020},
+ {0x01, 0x00ff, 0x003e},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0060, 0x0057},
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059},
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x100a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x000c, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0000, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021},
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023},
+ {0x00, 0x0000, 0x0024},
+ {0x00, 0x00d5, 0x0025},
+ {0x00, 0x0000, 0x0026},
+ {0x00, 0x000b, 0x0027},
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+ {0xff, 0x0000, 0x00d0},
+ {0xff, 0x00d8, 0x00d1},
+ {0xff, 0x0000, 0x00d4},
+ {0xff, 0x0000, 0x00d5},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003},
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0x00fd, 0x000a},
+ {0x01, 0x0038, 0x000b},
+ {0x01, 0x00d1, 0x000c},
+ {0x01, 0x00f7, 0x000d},
+ {0x01, 0x00ed, 0x000e},
+ {0x01, 0x00d8, 0x000f},
+ {0x01, 0x0038, 0x0010},
+ {0x01, 0x00ff, 0x0015},
+ {0x01, 0x0001, 0x0016},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020},
+ {0x01, 0x00ff, 0x003e},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0060, 0x0057},
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059},
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x100a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0xfffd, 0x000a},
+ {0x01, 0x0023, 0x000b},
+ {0x01, 0xffea, 0x000c},
+ {0x01, 0xfff4, 0x000d},
+ {0x01, 0xfffc, 0x000e},
+ {0x01, 0xffe3, 0x000f},
+ {0x01, 0x001f, 0x0010},
+ {0x01, 0x00a8, 0x0001},
+ {0x01, 0x0067, 0x0007},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x00c8, 0x0015},
+ {0x01, 0x0032, 0x0016},
+ {0x01, 0x0000, 0x0011},
+ {0x01, 0x0000, 0x0012},
+ {0x01, 0x0000, 0x0013},
+ {0x01, 0x000a, 0x0003},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xc000, 0x0001},
+ {0x02, 0x0000, 0x0005},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x000c, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0000, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021},
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023},
+ {0x00, 0x0000, 0x0024},
+ {0x00, 0x00d5, 0x0025},
+ {0x00, 0x0000, 0x0026},
+ {0x00, 0x000b, 0x0027},
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+ {0xff, 0x0000, 0x00d0},
+ {0xff, 0x00d8, 0x00d1},
+ {0xff, 0x0000, 0x00d4},
+ {0xff, 0x0000, 0x00d5},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003},
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0x00fd, 0x000a},
+ {0x01, 0x0038, 0x000b},
+ {0x01, 0x00d1, 0x000c},
+ {0x01, 0x00f7, 0x000d},
+ {0x01, 0x00ed, 0x000e},
+ {0x01, 0x00d8, 0x000f},
+ {0x01, 0x0038, 0x0010},
+ {0x01, 0x00ff, 0x0015},
+ {0x01, 0x0001, 0x0016},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020},
+ {0x01, 0x00ff, 0x003e},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0060, 0x0057},
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059},
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x100a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x000c, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0000, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021},
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023},
+ {0x00, 0x0000, 0x0024},
+ {0x00, 0x00d5, 0x0025},
+ {0x00, 0x0000, 0x0026},
+ {0x00, 0x000b, 0x0027},
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+ {0xff, 0x0000, 0x00d0},
+ {0xff, 0x00d8, 0x00d1},
+ {0xff, 0x0000, 0x00d4},
+ {0xff, 0x0000, 0x00d5},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003},
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0x00fd, 0x000a},
+ {0x01, 0x0038, 0x000b},
+ {0x01, 0x00d1, 0x000c},
+ {0x01, 0x00f7, 0x000d},
+ {0x01, 0x00ed, 0x000e},
+ {0x01, 0x00d8, 0x000f},
+ {0x01, 0x0038, 0x0010},
+ {0x01, 0x00ff, 0x0015},
+ {0x01, 0x0001, 0x0016},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020},
+ {0x01, 0x00ff, 0x003e},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0060, 0x0057},
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059},
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x100a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x000f, 0x0000},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0xfffd, 0x000a},
+ {0x01, 0x0023, 0x000b},
+ {0x01, 0xffea, 0x000c},
+ {0x01, 0xfff4, 0x000d},
+ {0x01, 0xfffc, 0x000e},
+ {0x01, 0xffe3, 0x000f},
+ {0x01, 0x001f, 0x0010},
+ {0x01, 0x00a8, 0x0001},
+ {0x01, 0x0067, 0x0007},
+ {0x01, 0x0042, 0x0051},
+ {0x01, 0x0051, 0x0053},
+ {0x01, 0x000a, 0x0003},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xc000, 0x0001},
+ {0x02, 0x0000, 0x0005},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x000c, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0000, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021},
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023},
+ {0x00, 0x0000, 0x0024},
+ {0x00, 0x00d5, 0x0025},
+ {0x00, 0x0000, 0x0026},
+ {0x00, 0x000b, 0x0027},
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+ {0xff, 0x0000, 0x00d0},
+ {0xff, 0x00d8, 0x00d1},
+ {0xff, 0x0000, 0x00d4},
+ {0xff, 0x0000, 0x00d5},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003},
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0x00fd, 0x000a},
+ {0x01, 0x0038, 0x000b},
+ {0x01, 0x00d1, 0x000c},
+ {0x01, 0x00f7, 0x000d},
+ {0x01, 0x00ed, 0x000e},
+ {0x01, 0x00d8, 0x000f},
+ {0x01, 0x0038, 0x0010},
+ {0x01, 0x00ff, 0x0015},
+ {0x01, 0x0001, 0x0016},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020},
+ {0x01, 0x00ff, 0x003e},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0060, 0x0057},
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059},
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x100a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x000c, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0000, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021},
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023},
+ {0x00, 0x0000, 0x0024},
+ {0x00, 0x00d5, 0x0025},
+ {0x00, 0x0000, 0x0026},
+ {0x00, 0x000b, 0x0027},
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+ {0xff, 0x0000, 0x00d0},
+ {0xff, 0x00d8, 0x00d1},
+ {0xff, 0x0000, 0x00d4},
+ {0xff, 0x0000, 0x00d5},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003},
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0x00fd, 0x000a},
+ {0x01, 0x0038, 0x000b},
+ {0x01, 0x00d1, 0x000c},
+ {0x01, 0x00f7, 0x000d},
+ {0x01, 0x00ed, 0x000e},
+ {0x01, 0x00d8, 0x000f},
+ {0x01, 0x0038, 0x0010},
+ {0x01, 0x00ff, 0x0015},
+ {0x01, 0x0001, 0x0016},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020},
+ {0x01, 0x00ff, 0x003e},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0060, 0x0057},
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059},
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x100a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x001e, 0x0000},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0xfffd, 0x000a},
+ {0x01, 0x0023, 0x000b},
+ {0x01, 0xffea, 0x000c},
+ {0x01, 0xfff4, 0x000d},
+ {0x01, 0xfffc, 0x000e},
+ {0x01, 0xffe3, 0x000f},
+ {0x01, 0x001f, 0x0010},
+ {0x01, 0x00a8, 0x0001},
+ {0x01, 0x0067, 0x0007},
+ {0x01, 0x0042, 0x0051},
+ {0x01, 0x0051, 0x0053},
+ {0x01, 0x000a, 0x0003},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x0007, 0x0005},
+ {0x01, 0x0042, 0x0051},
+ {0x01, 0x0051, 0x0053},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x002d, 0x0000},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0001, 0x0056},
+ {0x02, 0xc000, 0x0001},
+ {0x02, 0x0000, 0x0005},
+ {}
+};
+
+/* Unknow camera from Ori Usbid 0x0000:0x0000 */
+/* Based on snoops from Ori Cohen */
+static const __u16 spca501c_mysterious_open_data[][3] = {
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+/* DSP Registers */
+ {0x01, 0x0016, 0x0011}, /* RGB offset */
+ {0x01, 0x0000, 0x0012},
+ {0x01, 0x0006, 0x0013},
+ {0x01, 0x0078, 0x0051},
+ {0x01, 0x0040, 0x0052},
+ {0x01, 0x0046, 0x0053},
+ {0x01, 0x0040, 0x0054},
+ {0x00, 0x0025, 0x0000},
+/* {0x00, 0x0000, 0x0000 }, */
+/* Part 2 */
+/* TG Registers */
+ {0x00, 0x0026, 0x0000},
+ {0x00, 0x0001, 0x0000},
+ {0x00, 0x0027, 0x0000},
+ {0x00, 0x008a, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {}
+};
+
+/* Based on snoops from Ori Cohen */
+static const __u16 spca501c_mysterious_init_data[][3] = {
+/* Part 3 */
+/* TG registers */
+/* {0x00, 0x0000, 0x0000}, */
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x0006, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0001, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021}, /* 640 */
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023}, /* 480 */
+ {0x00, 0x0000, 0x0024}, /* Offset H hight */
+ {0x00, 0x00d3, 0x0025}, /* low */
+ {0x00, 0x0000, 0x0026}, /* Offset V */
+ {0x00, 0x000d, 0x0027}, /* low */
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+/* DSP Registers */
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003}, /* Level Calc bit7 ->1 Auto */
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x000f, 0x0008}, /* A11 Color correction coeff */
+ {0x01, 0x002d, 0x0009}, /* A12 */
+ {0x01, 0x0005, 0x000a}, /* A13 */
+ {0x01, 0x0023, 0x000b}, /* A21 */
+ {0x01, 0x00e0, 0x000c}, /* A22 */
+ {0x01, 0x00fd, 0x000d}, /* A23 */
+ {0x01, 0x00f4, 0x000e}, /* A31 */
+ {0x01, 0x00e4, 0x000f}, /* A32 */
+ {0x01, 0x0028, 0x0010}, /* A33 */
+ {0x01, 0x00ff, 0x0015}, /* Reserved */
+ {0x01, 0x0001, 0x0016}, /* Reserved */
+ {0x01, 0x0032, 0x0017}, /* Win1 Start begin */
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020}, /* Win1 Start end */
+ {0x01, 0x00ff, 0x003e}, /* Reserved begin */
+ {0x01, 0x0002, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0003, 0x0056}, /* Reserved end */
+ {0x01, 0x0060, 0x0057}, /* Edge Gain */
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059}, /* Edge Bandwidth */
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x200a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc000, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+/* Part 4 */
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x02, 0x0000, 0x0005},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x004e, 0x0000},
+/* Part 5 */
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x000f, 0x0008},
+ {0x01, 0x002d, 0x0009},
+ {0x01, 0x0005, 0x000a},
+ {0x01, 0x0023, 0x000b},
+ {0x01, 0xffe0, 0x000c},
+ {0x01, 0xfffd, 0x000d},
+ {0x01, 0xfff4, 0x000e},
+ {0x01, 0xffe4, 0x000f},
+ {0x01, 0x0028, 0x0010},
+ {0x01, 0x00a8, 0x0001},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x00c8, 0x0015}, /* c8 Poids fort Luma */
+ {0x01, 0x0032, 0x0016}, /* 32 */
+ {0x01, 0x0016, 0x0011}, /* R 00 */
+ {0x01, 0x0016, 0x0012}, /* G 00 */
+ {0x01, 0x0016, 0x0013}, /* B 00 */
+ {0x01, 0x000a, 0x0003},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x0007, 0x0005},
+ {}
+};
+
+static int reg_write(struct usb_device *dev,
+ __u16 req, __u16 index, __u16 value)
+{
+ int ret;
+
+ ret = usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ req,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x",
+ req, index, value);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg write: error %d", ret);
+ return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct gspca_dev *gspca_dev,
+ __u16 req, /* bRequest */
+ __u16 index, /* wIndex */
+ __u16 length) /* wLength (1 or 2 only) */
+{
+ int ret;
+
+ gspca_dev->usb_buf[1] = 0;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index,
+ gspca_dev->usb_buf, length,
+ 500); /* timeout */
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_read err %d", ret);
+ return -1;
+ }
+ return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][3])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, i = 0;
+
+ while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+ ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+ if (ret < 0) {
+ PDEBUG(D_ERR,
+ "Reg write failed for 0x%02x,0x%02x,0x%02x",
+ data[i][0], data[i][1], data[i][2]);
+ return ret;
+ }
+ i++;
+ }
+ return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->brightness);
+ reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness);
+ reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u16 brightness;
+
+ brightness = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x11, 2);
+ sd->brightness = brightness << 1;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_write(gspca_dev->dev, 0x00, 0x00,
+ (sd->contrast >> 8) & 0xff);
+ reg_write(gspca_dev->dev, 0x00, 0x01,
+ sd->contrast & 0xff);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+/* spca50x->contrast = 0xaa01; */
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, sd->colors);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x0c, 2);
+/* sd->hue = (reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x13, */
+/* 2) & 0xFF) << 8; */
+}
+
+/* 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;
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ switch (vendor) {
+ case 0x0000: /* Unknow Camera */
+/* switch (product) { */
+/* case 0x0000: */
+ sd->subtype = MystFromOriUnknownCamera;
+/* break; */
+/* } */
+ break;
+ case 0x040a: /* Kodak cameras */
+/* switch (product) { */
+/* case 0x0002: */
+ sd->subtype = KodakDVC325;
+/* break; */
+/* } */
+ break;
+ case 0x0497: /* Smile International */
+/* switch (product) { */
+/* case 0xc001: */
+ sd->subtype = SmileIntlCamera;
+/* break; */
+/* } */
+ break;
+ case 0x0506: /* 3COM cameras */
+/* switch (product) { */
+/* case 0x00df: */
+ sd->subtype = ThreeComHomeConnectLite;
+/* break; */
+/* } */
+ break;
+ case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+ switch (product) {
+ case 0x0401:
+ sd->subtype = IntelCreateAndShare;
+ break;
+ case 0x0402:
+ sd->subtype = ViewQuestM318B;
+ break;
+ }
+ break;
+ case 0x1776: /* Arowana */
+/* switch (product) { */
+/* case 0x501c: */
+ sd->subtype = Arowana300KCMOSCamera;
+/* break; */
+/* } */
+ break;
+ }
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value;
+ sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value;
+
+ switch (sd->subtype) {
+ case Arowana300KCMOSCamera:
+ case SmileIntlCamera:
+ /* Arowana 300k CMOS Camera data */
+ if (write_vector(gspca_dev, spca501c_arowana_init_data))
+ goto error;
+ break;
+ case MystFromOriUnknownCamera:
+ /* UnKnow Ori CMOS Camera data */
+ if (write_vector(gspca_dev, spca501c_mysterious_open_data))
+ goto error;
+ break;
+ default:
+ /* generic spca501 init data */
+ if (write_vector(gspca_dev, spca501_init_data))
+ goto error;
+ break;
+ }
+ return 0;
+error:
+ return -EINVAL;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->subtype) {
+ case ThreeComHomeConnectLite:
+ /* Special handling for 3com data */
+ write_vector(gspca_dev, spca501_3com_open_data);
+ break;
+ case Arowana300KCMOSCamera:
+ case SmileIntlCamera:
+ /* Arowana 300k CMOS Camera data */
+ write_vector(gspca_dev, spca501c_arowana_open_data);
+ break;
+ case MystFromOriUnknownCamera:
+ /* UnKnow CMOS Camera data */
+ write_vector(gspca_dev, spca501c_mysterious_init_data);
+ break;
+ default:
+ /* Generic 501 open data */
+ write_vector(gspca_dev, spca501_open_data);
+ }
+ PDEBUG(D_STREAM, "Initializing SPCA501 finished");
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int mode;
+
+ /* memorize the wanted pixel format */
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+
+ /* Enable ISO packet machine CTRL reg=2,
+ * index=1 bitmask=0x2 (bit ordinal 1) */
+ reg_write(dev, SPCA50X_REG_USB, 0x6, 0x94);
+ switch (mode) {
+ case 0: /* 640x480 */
+ reg_write(dev, SPCA50X_REG_USB, 0x07, 0x004a);
+ break;
+ case 1: /* 320x240 */
+ reg_write(dev, SPCA50X_REG_USB, 0x07, 0x104a);
+ break;
+ default:
+/* case 2: * 160x120 */
+ reg_write(dev, SPCA50X_REG_USB, 0x07, 0x204a);
+ break;
+ }
+ reg_write(dev, SPCA501_REG_CTLRL, 0x01, 0x02);
+
+ /* HDG atleast the Intel CreateAndShare needs to have one of its
+ * brightness / contrast / color set otherwise it assumes what seems
+ * max contrast. Note that strange enough setting any of these is
+ * enough to fix the max contrast problem, to be sure we set all 3 */
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ setcolors(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ /* Disable ISO packet
+ * machine CTRL reg=2, index=1 bitmask=0x0 (bit ordinal 1) */
+ reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+ reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ switch (data[0]) {
+ case 0: /* start of frame */
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame,
+ data, 0);
+ data += SPCA501_OFFSET_DATA;
+ len -= SPCA501_OFFSET_DATA;
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, len);
+ return;
+ case 0xff: /* drop */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ data++;
+ len--;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x040a, 0x0002), DVNM("Kodak DVC-325")},
+ {USB_DEVICE(0x0497, 0xc001), DVNM("Smile International")},
+ {USB_DEVICE(0x0506, 0x00df), DVNM("3Com HomeConnect Lite")},
+ {USB_DEVICE(0x0733, 0x0401), DVNM("Intel Create and Share")},
+ {USB_DEVICE(0x0733, 0x0402), DVNM("ViewQuest M318B")},
+ {USB_DEVICE(0x1776, 0x501c), DVNM("Arowana 300K CMOS Camera")},
+ {USB_DEVICE(0x0000, 0x0000), DVNM("MystFromOri Unknow Camera")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c
new file mode 100644
index 00000000000..ddea6e140aa
--- /dev/null
+++ b/drivers/media/video/gspca/spca505.c
@@ -0,0 +1,951 @@
+/*
+ * SPCA505 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francis Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "spca505"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ int buflen;
+ unsigned char tmpbuf[640 * 480 * 3 / 2]; /* YYUV per line */
+ unsigned char tmpbuf2[640 * 480 * 2]; /* YUYV */
+
+ unsigned char brightness;
+
+ char subtype;
+#define IntelPCCameraPro 0
+#define Nxultra 1
+};
+
+/* 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);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 160 * 2,
+ .sizeimage = 160 * 120 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 5},
+ {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 176 * 2,
+ .sizeimage = 176 * 144 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 4},
+ {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 320 * 2,
+ .sizeimage = 320 * 240 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 352 * 2,
+ .sizeimage = 352 * 288 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 640 * 2,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+
+#define SPCA50X_REG_USB 0x02 /* spca505 501 */
+
+#define SPCA50X_USB_CTRL 0x00 /* spca505 */
+#define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */
+#define SPCA50X_REG_GLOBAL 0x03 /* spca505 */
+#define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */
+#define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */
+
+#define SPCA50X_GLOBAL_MISC1 0x01 /* 505 */
+#define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */
+#define SPCA50X_GMISC3_SAA7113RST 0x20 /* Not sure about this one spca505 */
+
+/*
+ * Data to initialize a SPCA505. Common to the CCD and external modes
+ */
+static const __u16 spca505_init_data[][3] = {
+ /* line bmRequest,value,index */
+ /* 1819 */
+ {SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3},
+ /* Sensor reset */
+ /* 1822 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3},
+ /* 1825 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1},
+ /* Block USB reset */
+ /* 1828 */ {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL,
+ SPCA50X_GLOBAL_MISC0},
+
+ /* 1831 */ {0x5, 0x01, 0x10},
+ /* Maybe power down some stuff */
+ /* 1834 */ {0x5, 0x0f, 0x11},
+
+ /* Setup internal CCD ? */
+ /* 1837 */ {0x6, 0x10, 0x08},
+ /* 1840 */ {0x6, 0x00, 0x09},
+ /* 1843 */ {0x6, 0x00, 0x0a},
+ /* 1846 */ {0x6, 0x00, 0x0b},
+ /* 1849 */ {0x6, 0x10, 0x0c},
+ /* 1852 */ {0x6, 0x00, 0x0d},
+ /* 1855 */ {0x6, 0x00, 0x0e},
+ /* 1858 */ {0x6, 0x00, 0x0f},
+ /* 1861 */ {0x6, 0x10, 0x10},
+ /* 1864 */ {0x6, 0x02, 0x11},
+ /* 1867 */ {0x6, 0x00, 0x12},
+ /* 1870 */ {0x6, 0x04, 0x13},
+ /* 1873 */ {0x6, 0x02, 0x14},
+ /* 1876 */ {0x6, 0x8a, 0x51},
+ /* 1879 */ {0x6, 0x40, 0x52},
+ /* 1882 */ {0x6, 0xb6, 0x53},
+ /* 1885 */ {0x6, 0x3d, 0x54},
+ {}
+};
+
+/*
+ * Data to initialize the camera using the internal CCD
+ */
+static const __u16 spca505_open_data_ccd[][3] = {
+ /* line bmRequest,value,index */
+ /* Internal CCD data set */
+ /* 1891 */ {0x3, 0x04, 0x01},
+ /* This could be a reset */
+ /* 1894 */ {0x3, 0x00, 0x01},
+
+ /* Setup compression and image registers. 0x6 and 0x7 seem to be
+ related to H&V hold, and are resolution mode specific */
+ /* 1897 */ {0x4, 0x10, 0x01},
+ /* DIFF(0x50), was (0x10) */
+ /* 1900 */ {0x4, 0x00, 0x04},
+ /* 1903 */ {0x4, 0x00, 0x05},
+ /* 1906 */ {0x4, 0x20, 0x06},
+ /* 1909 */ {0x4, 0x20, 0x07},
+
+ /* 1912 */ {0x8, 0x0a, 0x00},
+ /* DIFF (0x4a), was (0xa) */
+
+ /* 1915 */ {0x5, 0x00, 0x10},
+ /* 1918 */ {0x5, 0x00, 0x11},
+ /* 1921 */ {0x5, 0x00, 0x00},
+ /* DIFF not written */
+ /* 1924 */ {0x5, 0x00, 0x01},
+ /* DIFF not written */
+ /* 1927 */ {0x5, 0x00, 0x02},
+ /* DIFF not written */
+ /* 1930 */ {0x5, 0x00, 0x03},
+ /* DIFF not written */
+ /* 1933 */ {0x5, 0x00, 0x04},
+ /* DIFF not written */
+ /* 1936 */ {0x5, 0x80, 0x05},
+ /* DIFF not written */
+ /* 1939 */ {0x5, 0xe0, 0x06},
+ /* DIFF not written */
+ /* 1942 */ {0x5, 0x20, 0x07},
+ /* DIFF not written */
+ /* 1945 */ {0x5, 0xa0, 0x08},
+ /* DIFF not written */
+ /* 1948 */ {0x5, 0x0, 0x12},
+ /* DIFF not written */
+ /* 1951 */ {0x5, 0x02, 0x0f},
+ /* DIFF not written */
+ /* 1954 */ {0x5, 0x10, 0x46},
+ /* DIFF not written */
+ /* 1957 */ {0x5, 0x8, 0x4a},
+ /* DIFF not written */
+
+ /* 1960 */ {0x3, 0x08, 0x03},
+ /* DIFF (0x3,0x28,0x3) */
+ /* 1963 */ {0x3, 0x08, 0x01},
+ /* 1966 */ {0x3, 0x0c, 0x03},
+ /* DIFF not written */
+ /* 1969 */ {0x3, 0x21, 0x00},
+ /* DIFF (0x39) */
+
+/* Extra block copied from init to hopefully ensure CCD is in a sane state */
+ /* 1837 */ {0x6, 0x10, 0x08},
+ /* 1840 */ {0x6, 0x00, 0x09},
+ /* 1843 */ {0x6, 0x00, 0x0a},
+ /* 1846 */ {0x6, 0x00, 0x0b},
+ /* 1849 */ {0x6, 0x10, 0x0c},
+ /* 1852 */ {0x6, 0x00, 0x0d},
+ /* 1855 */ {0x6, 0x00, 0x0e},
+ /* 1858 */ {0x6, 0x00, 0x0f},
+ /* 1861 */ {0x6, 0x10, 0x10},
+ /* 1864 */ {0x6, 0x02, 0x11},
+ /* 1867 */ {0x6, 0x00, 0x12},
+ /* 1870 */ {0x6, 0x04, 0x13},
+ /* 1873 */ {0x6, 0x02, 0x14},
+ /* 1876 */ {0x6, 0x8a, 0x51},
+ /* 1879 */ {0x6, 0x40, 0x52},
+ /* 1882 */ {0x6, 0xb6, 0x53},
+ /* 1885 */ {0x6, 0x3d, 0x54},
+ /* End of extra block */
+
+ /* 1972 */ {0x6, 0x3f, 0x1},
+ /* Block skipped */
+ /* 1975 */ {0x6, 0x10, 0x02},
+ /* 1978 */ {0x6, 0x64, 0x07},
+ /* 1981 */ {0x6, 0x10, 0x08},
+ /* 1984 */ {0x6, 0x00, 0x09},
+ /* 1987 */ {0x6, 0x00, 0x0a},
+ /* 1990 */ {0x6, 0x00, 0x0b},
+ /* 1993 */ {0x6, 0x10, 0x0c},
+ /* 1996 */ {0x6, 0x00, 0x0d},
+ /* 1999 */ {0x6, 0x00, 0x0e},
+ /* 2002 */ {0x6, 0x00, 0x0f},
+ /* 2005 */ {0x6, 0x10, 0x10},
+ /* 2008 */ {0x6, 0x02, 0x11},
+ /* 2011 */ {0x6, 0x00, 0x12},
+ /* 2014 */ {0x6, 0x04, 0x13},
+ /* 2017 */ {0x6, 0x02, 0x14},
+ /* 2020 */ {0x6, 0x8a, 0x51},
+ /* 2023 */ {0x6, 0x40, 0x52},
+ /* 2026 */ {0x6, 0xb6, 0x53},
+ /* 2029 */ {0x6, 0x3d, 0x54},
+ /* 2032 */ {0x6, 0x60, 0x57},
+ /* 2035 */ {0x6, 0x20, 0x58},
+ /* 2038 */ {0x6, 0x15, 0x59},
+ /* 2041 */ {0x6, 0x05, 0x5a},
+
+ /* 2044 */ {0x5, 0x01, 0xc0},
+ /* 2047 */ {0x5, 0x10, 0xcb},
+ /* 2050 */ {0x5, 0x80, 0xc1},
+ /* */
+ /* 2053 */ {0x5, 0x0, 0xc2},
+ /* 4 was 0 */
+ /* 2056 */ {0x5, 0x00, 0xca},
+ /* 2059 */ {0x5, 0x80, 0xc1},
+ /* */
+ /* 2062 */ {0x5, 0x04, 0xc2},
+ /* 2065 */ {0x5, 0x00, 0xca},
+ /* 2068 */ {0x5, 0x0, 0xc1},
+ /* */
+ /* 2071 */ {0x5, 0x00, 0xc2},
+ /* 2074 */ {0x5, 0x00, 0xca},
+ /* 2077 */ {0x5, 0x40, 0xc1},
+ /* */
+ /* 2080 */ {0x5, 0x17, 0xc2},
+ /* 2083 */ {0x5, 0x00, 0xca},
+ /* 2086 */ {0x5, 0x80, 0xc1},
+ /* */
+ /* 2089 */ {0x5, 0x06, 0xc2},
+ /* 2092 */ {0x5, 0x00, 0xca},
+ /* 2095 */ {0x5, 0x80, 0xc1},
+ /* */
+ /* 2098 */ {0x5, 0x04, 0xc2},
+ /* 2101 */ {0x5, 0x00, 0xca},
+
+ /* 2104 */ {0x3, 0x4c, 0x3},
+ /* 2107 */ {0x3, 0x18, 0x1},
+
+ /* 2110 */ {0x6, 0x70, 0x51},
+ /* 2113 */ {0x6, 0xbe, 0x53},
+ /* 2116 */ {0x6, 0x71, 0x57},
+ /* 2119 */ {0x6, 0x20, 0x58},
+ /* 2122 */ {0x6, 0x05, 0x59},
+ /* 2125 */ {0x6, 0x15, 0x5a},
+
+ /* 2128 */ {0x4, 0x00, 0x08},
+ /* Compress = OFF (0x1 to turn on) */
+ /* 2131 */ {0x4, 0x12, 0x09},
+ /* 2134 */ {0x4, 0x21, 0x0a},
+ /* 2137 */ {0x4, 0x10, 0x0b},
+ /* 2140 */ {0x4, 0x21, 0x0c},
+ /* 2143 */ {0x4, 0x05, 0x00},
+ /* was 5 (Image Type ? ) */
+ /* 2146 */ {0x4, 0x00, 0x01},
+
+ /* 2149 */ {0x6, 0x3f, 0x01},
+
+ /* 2152 */ {0x4, 0x00, 0x04},
+ /* 2155 */ {0x4, 0x00, 0x05},
+ /* 2158 */ {0x4, 0x40, 0x06},
+ /* 2161 */ {0x4, 0x40, 0x07},
+
+ /* 2164 */ {0x6, 0x1c, 0x17},
+ /* 2167 */ {0x6, 0xe2, 0x19},
+ /* 2170 */ {0x6, 0x1c, 0x1b},
+ /* 2173 */ {0x6, 0xe2, 0x1d},
+ /* 2176 */ {0x6, 0xaa, 0x1f},
+ /* 2179 */ {0x6, 0x70, 0x20},
+
+ /* 2182 */ {0x5, 0x01, 0x10},
+ /* 2185 */ {0x5, 0x00, 0x11},
+ /* 2188 */ {0x5, 0x01, 0x00},
+ /* 2191 */ {0x5, 0x05, 0x01},
+ /* 2194 */ {0x5, 0x00, 0xc1},
+ /* */
+ /* 2197 */ {0x5, 0x00, 0xc2},
+ /* 2200 */ {0x5, 0x00, 0xca},
+
+ /* 2203 */ {0x6, 0x70, 0x51},
+ /* 2206 */ {0x6, 0xbe, 0x53},
+ {}
+};
+
+/*
+ Made by Tomasz Zablocki (skalamandra@poczta.onet.pl)
+ * SPCA505b chip based cameras initialization data
+ *
+ */
+/* jfm */
+#define initial_brightness 0x7f /* 0x0(white)-0xff(black) */
+/* #define initial_brightness 0x0 //0x0(white)-0xff(black) */
+/*
+ * Data to initialize a SPCA505. Common to the CCD and external modes
+ */
+static const __u16 spca505b_init_data[][3] = {
+/* start */
+ {0x02, 0x00, 0x00}, /* init */
+ {0x02, 0x00, 0x01},
+ {0x02, 0x00, 0x02},
+ {0x02, 0x00, 0x03},
+ {0x02, 0x00, 0x04},
+ {0x02, 0x00, 0x05},
+ {0x02, 0x00, 0x06},
+ {0x02, 0x00, 0x07},
+ {0x02, 0x00, 0x08},
+ {0x02, 0x00, 0x09},
+ {0x03, 0x00, 0x00},
+ {0x03, 0x00, 0x01},
+ {0x03, 0x00, 0x02},
+ {0x03, 0x00, 0x03},
+ {0x03, 0x00, 0x04},
+ {0x03, 0x00, 0x05},
+ {0x03, 0x00, 0x06},
+ {0x04, 0x00, 0x00},
+ {0x04, 0x00, 0x02},
+ {0x04, 0x00, 0x04},
+ {0x04, 0x00, 0x05},
+ {0x04, 0x00, 0x06},
+ {0x04, 0x00, 0x07},
+ {0x04, 0x00, 0x08},
+ {0x04, 0x00, 0x09},
+ {0x04, 0x00, 0x0a},
+ {0x04, 0x00, 0x0b},
+ {0x04, 0x00, 0x0c},
+ {0x07, 0x00, 0x00},
+ {0x07, 0x00, 0x03},
+ {0x08, 0x00, 0x00},
+ {0x08, 0x00, 0x01},
+ {0x08, 0x00, 0x02},
+ {0x00, 0x01, 0x00},
+ {0x00, 0x01, 0x01},
+ {0x00, 0x01, 0x34},
+ {0x00, 0x01, 0x35},
+ {0x06, 0x18, 0x08},
+ {0x06, 0xfc, 0x09},
+ {0x06, 0xfc, 0x0a},
+ {0x06, 0xfc, 0x0b},
+ {0x06, 0x18, 0x0c},
+ {0x06, 0xfc, 0x0d},
+ {0x06, 0xfc, 0x0e},
+ {0x06, 0xfc, 0x0f},
+ {0x06, 0x18, 0x10},
+ {0x06, 0xfe, 0x12},
+ {0x06, 0x00, 0x11},
+ {0x06, 0x00, 0x14},
+ {0x06, 0x00, 0x13},
+ {0x06, 0x28, 0x51},
+ {0x06, 0xff, 0x53},
+ {0x02, 0x00, 0x08},
+
+ {0x03, 0x00, 0x03},
+ {0x03, 0x10, 0x03},
+ {}
+};
+
+/*
+ * Data to initialize the camera using the internal CCD
+ */
+static const __u16 spca505b_open_data_ccd[][3] = {
+
+/* {0x02,0x00,0x00}, */
+ {0x03, 0x04, 0x01}, /* rst */
+ {0x03, 0x00, 0x01},
+ {0x03, 0x00, 0x00},
+ {0x03, 0x21, 0x00},
+ {0x03, 0x00, 0x04},
+ {0x03, 0x00, 0x03},
+ {0x03, 0x18, 0x03},
+ {0x03, 0x08, 0x01},
+ {0x03, 0x1c, 0x03},
+ {0x03, 0x5c, 0x03},
+ {0x03, 0x5c, 0x03},
+ {0x03, 0x18, 0x01},
+
+/* same as 505 */
+ {0x04, 0x10, 0x01},
+ {0x04, 0x00, 0x04},
+ {0x04, 0x00, 0x05},
+ {0x04, 0x20, 0x06},
+ {0x04, 0x20, 0x07},
+
+ {0x08, 0x0a, 0x00},
+
+ {0x05, 0x00, 0x10},
+ {0x05, 0x00, 0x11},
+ {0x05, 0x00, 0x12},
+ {0x05, 0x6f, 0x00},
+ {0x05, initial_brightness >> 6, 0x00},
+ {0x05, initial_brightness << 2, 0x01},
+ {0x05, 0x00, 0x02},
+ {0x05, 0x01, 0x03},
+ {0x05, 0x00, 0x04},
+ {0x05, 0x03, 0x05},
+ {0x05, 0xe0, 0x06},
+ {0x05, 0x20, 0x07},
+ {0x05, 0xa0, 0x08},
+ {0x05, 0x00, 0x12},
+ {0x05, 0x02, 0x0f},
+ {0x05, 128, 0x14}, /* max exposure off (0=on) */
+ {0x05, 0x01, 0xb0},
+ {0x05, 0x01, 0xbf},
+ {0x03, 0x02, 0x06},
+ {0x05, 0x10, 0x46},
+ {0x05, 0x08, 0x4a},
+
+ {0x06, 0x00, 0x01},
+ {0x06, 0x10, 0x02},
+ {0x06, 0x64, 0x07},
+ {0x06, 0x18, 0x08},
+ {0x06, 0xfc, 0x09},
+ {0x06, 0xfc, 0x0a},
+ {0x06, 0xfc, 0x0b},
+ {0x04, 0x00, 0x01},
+ {0x06, 0x18, 0x0c},
+ {0x06, 0xfc, 0x0d},
+ {0x06, 0xfc, 0x0e},
+ {0x06, 0xfc, 0x0f},
+ {0x06, 0x11, 0x10}, /* contrast */
+ {0x06, 0x00, 0x11},
+ {0x06, 0xfe, 0x12},
+ {0x06, 0x00, 0x13},
+ {0x06, 0x00, 0x14},
+ {0x06, 0x9d, 0x51},
+ {0x06, 0x40, 0x52},
+ {0x06, 0x7c, 0x53},
+ {0x06, 0x40, 0x54},
+ {0x06, 0x02, 0x57},
+ {0x06, 0x03, 0x58},
+ {0x06, 0x15, 0x59},
+ {0x06, 0x05, 0x5a},
+ {0x06, 0x03, 0x56},
+ {0x06, 0x02, 0x3f},
+ {0x06, 0x00, 0x40},
+ {0x06, 0x39, 0x41},
+ {0x06, 0x69, 0x42},
+ {0x06, 0x87, 0x43},
+ {0x06, 0x9e, 0x44},
+ {0x06, 0xb1, 0x45},
+ {0x06, 0xbf, 0x46},
+ {0x06, 0xcc, 0x47},
+ {0x06, 0xd5, 0x48},
+ {0x06, 0xdd, 0x49},
+ {0x06, 0xe3, 0x4a},
+ {0x06, 0xe8, 0x4b},
+ {0x06, 0xed, 0x4c},
+ {0x06, 0xf2, 0x4d},
+ {0x06, 0xf7, 0x4e},
+ {0x06, 0xfc, 0x4f},
+ {0x06, 0xff, 0x50},
+
+ {0x05, 0x01, 0xc0},
+ {0x05, 0x10, 0xcb},
+ {0x05, 0x40, 0xc1},
+ {0x05, 0x04, 0xc2},
+ {0x05, 0x00, 0xca},
+ {0x05, 0x40, 0xc1},
+ {0x05, 0x09, 0xc2},
+ {0x05, 0x00, 0xca},
+ {0x05, 0xc0, 0xc1},
+ {0x05, 0x09, 0xc2},
+ {0x05, 0x00, 0xca},
+ {0x05, 0x40, 0xc1},
+ {0x05, 0x59, 0xc2},
+ {0x05, 0x00, 0xca},
+ {0x04, 0x00, 0x01},
+ {0x05, 0x80, 0xc1},
+ {0x05, 0xec, 0xc2},
+ {0x05, 0x0, 0xca},
+
+ {0x06, 0x02, 0x57},
+ {0x06, 0x01, 0x58},
+ {0x06, 0x15, 0x59},
+ {0x06, 0x0a, 0x5a},
+ {0x06, 0x01, 0x57},
+ {0x06, 0x8a, 0x03},
+ {0x06, 0x0a, 0x6c},
+ {0x06, 0x30, 0x01},
+ {0x06, 0x20, 0x02},
+ {0x06, 0x00, 0x03},
+
+ {0x05, 0x8c, 0x25},
+
+ {0x06, 0x4d, 0x51}, /* maybe saturation (4d) */
+ {0x06, 0x84, 0x53}, /* making green (84) */
+ {0x06, 0x00, 0x57}, /* sharpness (1) */
+ {0x06, 0x18, 0x08},
+ {0x06, 0xfc, 0x09},
+ {0x06, 0xfc, 0x0a},
+ {0x06, 0xfc, 0x0b},
+ {0x06, 0x18, 0x0c}, /* maybe hue (18) */
+ {0x06, 0xfc, 0x0d},
+ {0x06, 0xfc, 0x0e},
+ {0x06, 0xfc, 0x0f},
+ {0x06, 0x18, 0x10}, /* maybe contrast (18) */
+
+ {0x05, 0x01, 0x02},
+
+ {0x04, 0x00, 0x08}, /* compression */
+ {0x04, 0x12, 0x09},
+ {0x04, 0x21, 0x0a},
+ {0x04, 0x10, 0x0b},
+ {0x04, 0x21, 0x0c},
+ {0x04, 0x1d, 0x00}, /* imagetype (1d) */
+ {0x04, 0x41, 0x01}, /* hardware snapcontrol */
+
+ {0x04, 0x00, 0x04},
+ {0x04, 0x00, 0x05},
+ {0x04, 0x10, 0x06},
+ {0x04, 0x10, 0x07},
+ {0x04, 0x40, 0x06},
+ {0x04, 0x40, 0x07},
+ {0x04, 0x00, 0x04},
+ {0x04, 0x00, 0x05},
+
+ {0x06, 0x1c, 0x17},
+ {0x06, 0xe2, 0x19},
+ {0x06, 0x1c, 0x1b},
+ {0x06, 0xe2, 0x1d},
+ {0x06, 0x5f, 0x1f},
+ {0x06, 0x32, 0x20},
+
+ {0x05, initial_brightness >> 6, 0x00},
+ {0x05, initial_brightness << 2, 0x01},
+ {0x05, 0x06, 0xc1},
+ {0x05, 0x58, 0xc2},
+ {0x05, 0x0, 0xca},
+ {0x05, 0x0, 0x11},
+ {}
+};
+
+static int reg_write(struct usb_device *dev,
+ __u16 reg, __u16 index, __u16 value)
+{
+ int ret;
+
+ ret = usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ reg,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ PDEBUG(D_PACK, "reg write: 0x%02x,0x%02x:0x%02x, 0x%x",
+ reg, index, value, ret);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg write: error %d", ret);
+ return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct gspca_dev *gspca_dev,
+ __u16 reg, /* bRequest */
+ __u16 index, /* wIndex */
+ __u16 length) /* wLength (1 or 2 only) */
+{
+ int ret;
+
+ gspca_dev->usb_buf[1] = 0;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ reg,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ (__u16) 0, /* value */
+ (__u16) index,
+ gspca_dev->usb_buf, length,
+ 500); /* timeout */
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_read err %d", ret);
+ return -1;
+ }
+ return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][3])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, i = 0;
+
+ while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+ ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+ if (ret < 0) {
+ PDEBUG(D_ERR,
+ "Register write failed for 0x%x,0x%x,0x%x",
+ data[i][0], data[i][1], data[i][2]);
+ return ret;
+ }
+ i++;
+ }
+ return 0;
+}
+
+/* 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;
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ switch (vendor) {
+ case 0x041e: /* Creative cameras */
+/* switch (product) { */
+/* case 0x401d: * here505b */
+ sd->subtype = Nxultra;
+/* break; */
+/* } */
+ break;
+ case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+/* switch (product) { */
+/* case 0x0430: */
+/* fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */
+ sd->subtype = IntelPCCameraPro;
+/* break; */
+/* } */
+ break;
+ }
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ if (sd->subtype != IntelPCCameraPro)
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ else /* no 640x480 for IntelPCCameraPro */
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0] - 1;
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+
+ if (sd->subtype == Nxultra) {
+ if (write_vector(gspca_dev, spca505b_init_data))
+ return -EIO;
+ } else {
+ if (write_vector(gspca_dev, spca505_init_data))
+ return -EIO;
+ }
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ PDEBUG(D_STREAM, "Initializing SPCA505");
+ if (sd->subtype == Nxultra)
+ write_vector(gspca_dev, spca505b_open_data_ccd);
+ else
+ write_vector(gspca_dev, spca505_open_data_ccd);
+ ret = reg_read(gspca_dev, 6, 0x16, 2);
+
+ if (ret < 0) {
+ PDEBUG(D_ERR|D_STREAM,
+ "register read failed for after vector read err = %d",
+ ret);
+ return -EIO;
+ }
+ PDEBUG(D_STREAM,
+ "After vector read returns : 0x%x should be 0x0101",
+ ret & 0xffff);
+
+ ret = reg_write(gspca_dev->dev, 6, 0x16, 0x0a);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "register write failed for (6,0xa,0x16) err=%d",
+ ret);
+ return -EIO;
+ }
+ reg_write(gspca_dev->dev, 5, 0xc2, 18);
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ /* necessary because without it we can see stream
+ * only once after loading module */
+ /* stopping usb registers Tomasz change */
+ reg_write(dev, 0x02, 0x0, 0x0);
+ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ case 0:
+ reg_write(dev, 0x04, 0x00, 0x00);
+ reg_write(dev, 0x04, 0x06, 0x10);
+ reg_write(dev, 0x04, 0x07, 0x10);
+ break;
+ case 1:
+ reg_write(dev, 0x04, 0x00, 0x01);
+ reg_write(dev, 0x04, 0x06, 0x1a);
+ reg_write(dev, 0x04, 0x07, 0x1a);
+ break;
+ case 2:
+ reg_write(dev, 0x04, 0x00, 0x02);
+ reg_write(dev, 0x04, 0x06, 0x1c);
+ reg_write(dev, 0x04, 0x07, 0x1d);
+ break;
+ case 4:
+ reg_write(dev, 0x04, 0x00, 0x04);
+ reg_write(dev, 0x04, 0x06, 0x34);
+ reg_write(dev, 0x04, 0x07, 0x34);
+ break;
+ default:
+/* case 5: */
+ reg_write(dev, 0x04, 0x00, 0x05);
+ reg_write(dev, 0x04, 0x06, 0x40);
+ reg_write(dev, 0x04, 0x07, 0x40);
+ break;
+ }
+/* Enable ISO packet machine - should we do this here or in ISOC init ? */
+ ret = reg_write(dev, SPCA50X_REG_USB,
+ SPCA50X_USB_CTRL,
+ SPCA50X_CUSB_ENABLE);
+
+/* reg_write(dev, 0x5, 0x0, 0x0); */
+/* reg_write(dev, 0x5, 0x0, 0x1); */
+/* reg_write(dev, 0x5, 0x11, 0x2); */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ /* Disable ISO packet machine */
+ reg_write(gspca_dev->dev, 0x02, 0x00, 0x00);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+ /* This maybe reset or power control */
+ reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
+ reg_write(gspca_dev->dev, 0x03, 0x01, 0x0);
+ reg_write(gspca_dev->dev, 0x03, 0x00, 0x1);
+ reg_write(gspca_dev->dev, 0x05, 0x10, 0x1);
+ reg_write(gspca_dev->dev, 0x05, 0x11, 0xf);
+}
+
+/* convert YYUV per line to YUYV (YUV 4:2:2) */
+static void yyuv_decode(unsigned char *out,
+ unsigned char *in,
+ int width,
+ int height)
+{
+ unsigned char *Ui, *Vi, *yi, *yi1;
+ unsigned char *out1;
+ int i, j;
+
+ yi = in;
+ for (i = height / 2; --i >= 0; ) {
+ out1 = out + width * 2; /* next line */
+ yi1 = yi + width;
+ Ui = yi1 + width;
+ Vi = Ui + width / 2;
+ for (j = width / 2; --j >= 0; ) {
+ *out++ = 128 + *yi++;
+ *out++ = 128 + *Ui;
+ *out++ = 128 + *yi++;
+ *out++ = 128 + *Vi;
+
+ *out1++ = 128 + *yi1++;
+ *out1++ = 128 + *Ui++;
+ *out1++ = 128 + *yi1++;
+ *out1++ = 128 + *Vi++;
+ }
+ yi += width * 2;
+ out = out1;
+ }
+}
+
+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 (data[0]) {
+ case 0: /* start of frame */
+ if (gspca_dev->last_packet_type == FIRST_PACKET) {
+ yyuv_decode(sd->tmpbuf2, sd->tmpbuf,
+ gspca_dev->width,
+ gspca_dev->height);
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame,
+ sd->tmpbuf2,
+ gspca_dev->width
+ * gspca_dev->height
+ * 2);
+ }
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, 0);
+ data += SPCA50X_OFFSET_DATA;
+ len -= SPCA50X_OFFSET_DATA;
+ if (len > 0)
+ memcpy(sd->tmpbuf, data, len);
+ else
+ len = 0;
+ sd->buflen = len;
+ return;
+ case 0xff: /* drop */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ data += 1;
+ len -= 1;
+ memcpy(&sd->tmpbuf[sd->buflen], data, len);
+ sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ __u8 brightness = sd->brightness;
+ reg_write(gspca_dev->dev, 5, 0x00, (255 - brightness) >> 6);
+ reg_write(gspca_dev->dev, 5, 0x01, (255 - brightness) << 2);
+
+}
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = 255
+ - ((reg_read(gspca_dev, 5, 0x01, 1) >> 2)
+ + (reg_read(gspca_dev, 5, 0x0, 1) << 6));
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x401d), DVNM("Creative Webcam NX ULTRA")},
+ {USB_DEVICE(0x0733, 0x0430), DVNM("Intel PC Camera Pro")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c
new file mode 100644
index 00000000000..143203c1fd9
--- /dev/null
+++ b/drivers/media/video/gspca/spca506.c
@@ -0,0 +1,847 @@
+/*
+ * SPCA506 chip based cameras function
+ * M Xhaard 15/04/2004 based on different work Mark Taylor and others
+ * and my own snoopy file on a pv-321c donate by a german compagny
+ * "Firma Frank Gmbh" from Saarbruecken
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca506"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA506 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ int buflen;
+ __u8 tmpbuf[640 * 480 * 3]; /* YYUV per line */
+ __u8 tmpbuf2[640 * 480 * 2]; /* YUYV */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char hue;
+ char norme;
+ char channel;
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x80,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x47,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_COLOR 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x40,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+#define SD_HUE 3
+ {
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = sd_sethue,
+ .get = sd_gethue,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 160 * 2,
+ .sizeimage = 160 * 120 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 5},
+ {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 176 * 2,
+ .sizeimage = 176 * 144 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 4},
+ {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 320 * 2,
+ .sizeimage = 320 * 240 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 352 * 2,
+ .sizeimage = 352 * 288 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 640 * 2,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+
+#define SAA7113_bright 0x0a /* defaults 0x80 */
+#define SAA7113_contrast 0x0b /* defaults 0x47 */
+#define SAA7113_saturation 0x0c /* defaults 0x40 */
+#define SAA7113_hue 0x0d /* defaults 0x00 */
+#define SAA7113_I2C_BASE_WRITE 0x4a
+
+/* read 'len' bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+ __u16 req,
+ __u16 index,
+ __u16 length)
+{
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, length,
+ 500);
+}
+
+static void reg_w(struct usb_device *dev,
+ __u16 req,
+ __u16 value,
+ __u16 index)
+{
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index,
+ NULL, 0, 500);
+}
+
+static void spca506_Initi2c(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);
+}
+
+static void spca506_WriteI2c(struct gspca_dev *gspca_dev, __u16 valeur,
+ __u16 reg)
+{
+ int retry = 60;
+
+ reg_w(gspca_dev->dev, 0x07, reg, 0x0001);
+ reg_w(gspca_dev->dev, 0x07, valeur, 0x0000);
+ while (retry--) {
+ reg_r(gspca_dev, 0x07, 0x0003, 2);
+ if ((gspca_dev->usb_buf[0] | gspca_dev->usb_buf[1]) == 0x00)
+ break;
+ }
+}
+
+static int spca506_ReadI2c(struct gspca_dev *gspca_dev, __u16 reg)
+{
+ int retry = 60;
+
+ reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);
+ reg_w(gspca_dev->dev, 0x07, reg, 0x0001);
+ reg_w(gspca_dev->dev, 0x07, 0x01, 0x0002);
+ while (--retry) {
+ reg_r(gspca_dev, 0x07, 0x0003, 2);
+ if ((gspca_dev->usb_buf[0] | gspca_dev->usb_buf[1]) == 0x00)
+ break;
+ }
+ if (retry == 0)
+ return -1;
+ reg_r(gspca_dev, 0x07, 0x0000, 1);
+ return gspca_dev->usb_buf[0];
+}
+
+static void spca506_SetNormeInput(struct gspca_dev *gspca_dev,
+ __u16 norme,
+ __u16 channel)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+/* fixme: check if channel == 0..3 and 6..9 (8 values) */
+ __u8 setbit0 = 0x00;
+ __u8 setbit1 = 0x00;
+ __u8 videomask = 0x00;
+
+ PDEBUG(D_STREAM, "** Open Set Norme **");
+ spca506_Initi2c(gspca_dev);
+ /* NTSC bit0 -> 1(525 l) PAL SECAM bit0 -> 0 (625 l) */
+ /* Composite channel bit1 -> 1 S-video bit 1 -> 0 */
+ /* and exclude SAA7113 reserved channel set default 0 otherwise */
+ if (norme & V4L2_STD_NTSC)
+ setbit0 = 0x01;
+ if (channel == 4 || channel == 5 || channel > 9)
+ channel = 0;
+ if (channel < 4)
+ setbit1 = 0x02;
+ videomask = (0x48 | setbit0 | setbit1);
+ reg_w(gspca_dev->dev, 0x08, videomask, 0x0000);
+ spca506_WriteI2c(gspca_dev, (0xc0 | (channel & 0x0F)), 0x02);
+
+ if (norme & V4L2_STD_NTSC)
+ spca506_WriteI2c(gspca_dev, 0x33, 0x0e);
+ /* Chrominance Control NTSC N */
+ else if (norme & V4L2_STD_SECAM)
+ spca506_WriteI2c(gspca_dev, 0x53, 0x0e);
+ /* Chrominance Control SECAM */
+ else
+ spca506_WriteI2c(gspca_dev, 0x03, 0x0e);
+ /* Chrominance Control PAL BGHIV */
+
+ sd->norme = norme;
+ sd->channel = channel;
+ PDEBUG(D_STREAM, "Set Video Byte to 0x%2x", videomask);
+ PDEBUG(D_STREAM, "Set Norme: %08x Channel %d", norme, channel);
+}
+
+static void spca506_GetNormeInput(struct gspca_dev *gspca_dev,
+ __u16 *norme, __u16 *channel)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* Read the register is not so good value change so
+ we use your own copy in spca50x struct */
+ *norme = sd->norme;
+ *channel = sd->channel;
+ PDEBUG(D_STREAM, "Get Norme: %d Channel %d", *norme, *channel);
+}
+
+static void spca506_Setsize(struct gspca_dev *gspca_dev, __u16 code,
+ __u16 xmult, __u16 ymult)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ PDEBUG(D_STREAM, "** SetSize **");
+ reg_w(dev, 0x04, (0x18 | (code & 0x07)), 0x0000);
+ /* Soft snap 0x40 Hard 0x41 */
+ reg_w(dev, 0x04, 0x41, 0x0001);
+ reg_w(dev, 0x04, 0x00, 0x0002);
+ /* reserved */
+ reg_w(dev, 0x04, 0x00, 0x0003);
+
+ /* reserved */
+ reg_w(dev, 0x04, 0x00, 0x0004);
+ /* reserved */
+ reg_w(dev, 0x04, 0x01, 0x0005);
+ /* reserced */
+ reg_w(dev, 0x04, xmult, 0x0006);
+ /* reserved */
+ reg_w(dev, 0x04, ymult, 0x0007);
+ /* compression 1 */
+ reg_w(dev, 0x04, 0x00, 0x0008);
+ /* T=64 -> 2 */
+ reg_w(dev, 0x04, 0x00, 0x0009);
+ /* threshold2D */
+ reg_w(dev, 0x04, 0x21, 0x000a);
+ /* quantization */
+ reg_w(dev, 0x04, 0x00, 0x000b);
+}
+
+/* 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;
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+ sd->hue = sd_ctrls[SD_HUE].qctrl.default_value;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ reg_w(dev, 0x03, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0xFF, 0x0003);
+ reg_w(dev, 0x03, 0x00, 0x0000);
+ reg_w(dev, 0x03, 0x1c, 0x0001);
+ reg_w(dev, 0x03, 0x18, 0x0001);
+ /* Init on PAL and composite input0 */
+ spca506_SetNormeInput(gspca_dev, 0, 0);
+ reg_w(dev, 0x03, 0x1c, 0x0001);
+ reg_w(dev, 0x03, 0x18, 0x0001);
+ reg_w(dev, 0x05, 0x00, 0x0000);
+ reg_w(dev, 0x05, 0xef, 0x0001);
+ reg_w(dev, 0x05, 0x00, 0x00c1);
+ reg_w(dev, 0x05, 0x00, 0x00c2);
+ reg_w(dev, 0x06, 0x18, 0x0002);
+ reg_w(dev, 0x06, 0xf5, 0x0011);
+ reg_w(dev, 0x06, 0x02, 0x0012);
+ reg_w(dev, 0x06, 0xfb, 0x0013);
+ reg_w(dev, 0x06, 0x00, 0x0014);
+ reg_w(dev, 0x06, 0xa4, 0x0051);
+ reg_w(dev, 0x06, 0x40, 0x0052);
+ reg_w(dev, 0x06, 0x71, 0x0053);
+ reg_w(dev, 0x06, 0x40, 0x0054);
+ /************************************************/
+ reg_w(dev, 0x03, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0x00, 0x0003);
+ reg_w(dev, 0x03, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0xFF, 0x0003);
+ reg_w(dev, 0x02, 0x00, 0x0000);
+ reg_w(dev, 0x03, 0x60, 0x0000);
+ reg_w(dev, 0x03, 0x18, 0x0001);
+ /* for a better reading mx :) */
+ /*sdca506_WriteI2c(value,register) */
+ spca506_Initi2c(gspca_dev);
+ spca506_WriteI2c(gspca_dev, 0x08, 0x01);
+ spca506_WriteI2c(gspca_dev, 0xc0, 0x02);
+ /* input composite video */
+ spca506_WriteI2c(gspca_dev, 0x33, 0x03);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x04);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x05);
+ spca506_WriteI2c(gspca_dev, 0x0d, 0x06);
+ spca506_WriteI2c(gspca_dev, 0xf0, 0x07);
+ spca506_WriteI2c(gspca_dev, 0x98, 0x08);
+ spca506_WriteI2c(gspca_dev, 0x03, 0x09);
+ spca506_WriteI2c(gspca_dev, 0x80, 0x0a);
+ spca506_WriteI2c(gspca_dev, 0x47, 0x0b);
+ spca506_WriteI2c(gspca_dev, 0x48, 0x0c);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x0d);
+ spca506_WriteI2c(gspca_dev, 0x03, 0x0e); /* Chroma Pal adjust */
+ spca506_WriteI2c(gspca_dev, 0x2a, 0x0f);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x10);
+ spca506_WriteI2c(gspca_dev, 0x0c, 0x11);
+ spca506_WriteI2c(gspca_dev, 0xb8, 0x12);
+ spca506_WriteI2c(gspca_dev, 0x01, 0x13);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x14);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x15);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x16);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x17);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x18);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x19);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1a);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1b);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1c);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1d);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1e);
+ spca506_WriteI2c(gspca_dev, 0xa1, 0x1f);
+ spca506_WriteI2c(gspca_dev, 0x02, 0x40);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x41);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x42);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x43);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x44);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x45);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x46);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x47);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x48);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x49);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4a);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4b);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4c);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4d);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4e);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4f);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x50);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x51);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x52);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x53);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x54);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x55);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x56);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x57);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x58);
+ spca506_WriteI2c(gspca_dev, 0x54, 0x59);
+ spca506_WriteI2c(gspca_dev, 0x07, 0x5a);
+ spca506_WriteI2c(gspca_dev, 0x83, 0x5b);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5c);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5d);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5e);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5f);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x60);
+ spca506_WriteI2c(gspca_dev, 0x05, 0x61);
+ spca506_WriteI2c(gspca_dev, 0x9f, 0x62);
+ PDEBUG(D_STREAM, "** Close Init *");
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u16 norme;
+ __u16 channel;
+
+ /**************************************/
+ reg_w(dev, 0x03, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0x00, 0x0003);
+ reg_w(dev, 0x03, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0xFF, 0x0003);
+ reg_w(dev, 0x02, 0x00, 0x0000);
+ reg_w(dev, 0x03, 0x60, 0x0000);
+ reg_w(dev, 0x03, 0x18, 0x0001);
+
+ /*sdca506_WriteI2c(value,register) */
+ spca506_Initi2c(gspca_dev);
+ spca506_WriteI2c(gspca_dev, 0x08, 0x01); /* Increment Delay */
+/* spca506_WriteI2c(gspca_dev, 0xc0, 0x02); * Analog Input Control 1 */
+ spca506_WriteI2c(gspca_dev, 0x33, 0x03);
+ /* Analog Input Control 2 */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x04);
+ /* Analog Input Control 3 */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x05);
+ /* Analog Input Control 4 */
+ spca506_WriteI2c(gspca_dev, 0x0d, 0x06);
+ /* Horizontal Sync Start 0xe9-0x0d */
+ spca506_WriteI2c(gspca_dev, 0xf0, 0x07);
+ /* Horizontal Sync Stop 0x0d-0xf0 */
+
+ spca506_WriteI2c(gspca_dev, 0x98, 0x08); /* Sync Control */
+/* Defaults value */
+ spca506_WriteI2c(gspca_dev, 0x03, 0x09); /* Luminance Control */
+ spca506_WriteI2c(gspca_dev, 0x80, 0x0a);
+ /* Luminance Brightness */
+ spca506_WriteI2c(gspca_dev, 0x47, 0x0b); /* Luminance Contrast */
+ spca506_WriteI2c(gspca_dev, 0x48, 0x0c);
+ /* Chrominance Saturation */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x0d);
+ /* Chrominance Hue Control */
+ spca506_WriteI2c(gspca_dev, 0x2a, 0x0f);
+ /* Chrominance Gain Control */
+ /**************************************/
+ spca506_WriteI2c(gspca_dev, 0x00, 0x10);
+ /* Format/Delay Control */
+ spca506_WriteI2c(gspca_dev, 0x0c, 0x11); /* Output Control 1 */
+ spca506_WriteI2c(gspca_dev, 0xb8, 0x12); /* Output Control 2 */
+ spca506_WriteI2c(gspca_dev, 0x01, 0x13); /* Output Control 3 */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x14); /* reserved */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x15); /* VGATE START */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x16); /* VGATE STOP */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x17); /* VGATE Control (MSB) */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x18);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x19);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1a);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1b);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1c);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1d);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1e);
+ spca506_WriteI2c(gspca_dev, 0xa1, 0x1f);
+ spca506_WriteI2c(gspca_dev, 0x02, 0x40);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x41);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x42);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x43);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x44);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x45);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x46);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x47);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x48);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x49);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4a);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4b);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4c);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4d);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4e);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4f);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x50);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x51);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x52);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x53);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x54);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x55);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x56);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x57);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x58);
+ spca506_WriteI2c(gspca_dev, 0x54, 0x59);
+ spca506_WriteI2c(gspca_dev, 0x07, 0x5a);
+ spca506_WriteI2c(gspca_dev, 0x83, 0x5b);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5c);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5d);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5e);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5f);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x60);
+ spca506_WriteI2c(gspca_dev, 0x05, 0x61);
+ spca506_WriteI2c(gspca_dev, 0x9f, 0x62);
+ /**************************************/
+ reg_w(dev, 0x05, 0x00, 0x0003);
+ reg_w(dev, 0x05, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0x10, 0x0001);
+ reg_w(dev, 0x03, 0x78, 0x0000);
+ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ case 0:
+ spca506_Setsize(gspca_dev, 0, 0x10, 0x10);
+ break;
+ case 1:
+ spca506_Setsize(gspca_dev, 1, 0x1a, 0x1a);
+ break;
+ case 2:
+ spca506_Setsize(gspca_dev, 2, 0x1c, 0x1c);
+ break;
+ case 4:
+ spca506_Setsize(gspca_dev, 4, 0x34, 0x34);
+ break;
+ default:
+/* case 5: */
+ spca506_Setsize(gspca_dev, 5, 0x40, 0x40);
+ break;
+ }
+
+ /* compress setting and size */
+ /* set i2c luma */
+ reg_w(dev, 0x02, 0x01, 0x0000);
+ reg_w(dev, 0x03, 0x12, 0x0000);
+ reg_r(gspca_dev, 0x04, 0x0001, 2);
+ PDEBUG(D_STREAM, "webcam started");
+ spca506_GetNormeInput(gspca_dev, &norme, &channel);
+ spca506_SetNormeInput(gspca_dev, norme, channel);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ reg_w(dev, 0x02, 0x00, 0x0000);
+ reg_w(dev, 0x03, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0x00, 0x0003);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+/* convert YYUV per line to YUYV (YUV 4:2:2) */
+static void yyuv_decode(unsigned char *out,
+ unsigned char *in,
+ int width,
+ int height)
+{
+ unsigned char *Ui, *Vi, *yi, *yi1;
+ unsigned char *out1;
+ int i, j;
+
+ yi = in;
+ for (i = height / 2; --i >= 0; ) {
+ out1 = out + width * 2; /* next line */
+ yi1 = yi + width;
+ Ui = yi1 + width;
+ Vi = Ui + width / 2;
+ for (j = width / 2; --j >= 0; ) {
+ *out++ = 128 + *yi++;
+ *out++ = 128 + *Ui;
+ *out++ = 128 + *yi++;
+ *out++ = 128 + *Vi;
+
+ *out1++ = 128 + *yi1++;
+ *out1++ = 128 + *Ui++;
+ *out1++ = 128 + *yi1++;
+ *out1++ = 128 + *Vi++;
+ }
+ yi += width * 2;
+ out = out1;
+ }
+}
+
+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 (data[0]) {
+ case 0: /* start of frame */
+ if (gspca_dev->last_packet_type == FIRST_PACKET) {
+ yyuv_decode(sd->tmpbuf2, sd->tmpbuf,
+ gspca_dev->width,
+ gspca_dev->height);
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame,
+ sd->tmpbuf2,
+ gspca_dev->width
+ * gspca_dev->height
+ * 2);
+ }
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, 0);
+ data += SPCA50X_OFFSET_DATA;
+ len -= SPCA50X_OFFSET_DATA;
+ if (len > 0)
+ memcpy(sd->tmpbuf, data, len);
+ else
+ len = 0;
+ sd->buflen = len;
+ return;
+ case 0xff: /* drop */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ data += 1;
+ len -= 1;
+ memcpy(&sd->tmpbuf[sd->buflen], data, len);
+ sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ spca506_Initi2c(gspca_dev);
+ spca506_WriteI2c(gspca_dev, sd->brightness, SAA7113_bright);
+ spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = spca506_ReadI2c(gspca_dev, SAA7113_bright);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ spca506_Initi2c(gspca_dev);
+ spca506_WriteI2c(gspca_dev, sd->contrast, SAA7113_contrast);
+ spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = spca506_ReadI2c(gspca_dev, SAA7113_contrast);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ spca506_Initi2c(gspca_dev);
+ spca506_WriteI2c(gspca_dev, sd->colors, SAA7113_saturation);
+ spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = spca506_ReadI2c(gspca_dev, SAA7113_saturation);
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ spca506_Initi2c(gspca_dev);
+ spca506_WriteI2c(gspca_dev, sd->hue, SAA7113_hue);
+ spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void gethue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hue = spca506_ReadI2c(gspca_dev, SAA7113_hue);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hue = val;
+ if (gspca_dev->streaming)
+ sethue(gspca_dev);
+ return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gethue(gspca_dev);
+ *val = sd->hue;
+ return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x06e1, 0xa190), DVNM("ADS Instant VCD")},
+/* {USB_DEVICE(0x0733, 0x0430), DVNM("UsbGrabber PV321c")}, */
+ {USB_DEVICE(0x0734, 0x043b), DVNM("3DeMon USB Capture aka")},
+ {USB_DEVICE(0x99fa, 0x8988), DVNM("Grandtec V.cap")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
new file mode 100644
index 00000000000..d8cd93866a4
--- /dev/null
+++ b/drivers/media/video/gspca/spca508.c
@@ -0,0 +1,1791 @@
+/*
+ * SPCA508 chip based cameras subdriver
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca508"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA508 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ int buflen;
+ unsigned char tmpbuf[352 * 288 * 3 / 2]; /* YUVY per line */
+ unsigned char tmpbuf2[352 * 288 * 2]; /* YUYV */
+
+ unsigned char brightness;
+
+ char subtype;
+#define CreativeVista 0
+#define HamaUSBSightcam 1
+#define HamaUSBSightcam2 2
+#define IntelEasyPCCamera 3
+#define MicroInnovationIC200 4
+#define ViewQuestVQ110 5
+};
+
+/* 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);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 128
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 160 * 2,
+ .sizeimage = 160 * 120 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 3},
+ {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 176 * 2,
+ .sizeimage = 176 * 144 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 320 * 2,
+ .sizeimage = 320 * 240 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 352 * 2,
+ .sizeimage = 352 * 288 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+/* Frame packet header offsets for the spca508 */
+#define SPCA508_OFFSET_TYPE 1
+#define SPCA508_OFFSET_COMPRESS 2
+#define SPCA508_OFFSET_FRAMSEQ 8
+#define SPCA508_OFFSET_WIN1LUM 11
+#define SPCA508_OFFSET_DATA 37
+
+#define SPCA508_SNAPBIT 0x20
+#define SPCA508_SNAPCTRL 0x40
+/*************** I2c ****************/
+#define SPCA508_INDEX_I2C_BASE 0x8800
+
+/*
+ * Initialization data: this is the first set-up data written to the
+ * device (before the open data).
+ */
+static const __u16 spca508_init_data[][3] =
+#define IGN(x) /* nothing */
+{
+ /* line URB value, index */
+ /* 44274 1804 */ {0x0000, 0x870b},
+
+ /* 44299 1805 */ {0x0020, 0x8112},
+ /* Video drop enable, ISO streaming disable */
+ /* 44324 1806 */ {0x0003, 0x8111},
+ /* Reset compression & memory */
+ /* 44349 1807 */ {0x0000, 0x8110},
+ /* Disable all outputs */
+ /* 44372 1808 */ /* READ {0x0000, 0x8114} -> 0000: 00 */
+ /* 44398 1809 */ {0x0000, 0x8114},
+ /* SW GPIO data */
+ /* 44423 1810 */ {0x0008, 0x8110},
+ /* Enable charge pump output */
+ /* 44527 1811 */ {0x0002, 0x8116},
+ /* 200 kHz pump clock */
+ /* 44555 1812 */
+ /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */
+ /* 44590 1813 */ {0x0003, 0x8111},
+ /* Reset compression & memory */
+ /* 44615 1814 */ {0x0000, 0x8111},
+ /* Normal mode (not reset) */
+ /* 44640 1815 */ {0x0098, 0x8110},
+ /* Enable charge pump output, sync.serial,external 2x clock */
+ /* 44665 1816 */ {0x000d, 0x8114},
+ /* SW GPIO data */
+ /* 44690 1817 */ {0x0002, 0x8116},
+ /* 200 kHz pump clock */
+ /* 44715 1818 */ {0x0020, 0x8112},
+ /* Video drop enable, ISO streaming disable */
+/* --------------------------------------- */
+ /* 44740 1819 */ {0x000f, 0x8402},
+ /* memory bank */
+ /* 44765 1820 */ {0x0000, 0x8403},
+ /* ... address */
+/* --------------------------------------- */
+/* 0x88__ is Synchronous Serial Interface. */
+/* TBD: This table could be expressed more compactly */
+/* using spca508_write_i2c_vector(). */
+/* TBD: Should see if the values in spca50x_i2c_data */
+/* would work with the VQ110 instead of the values */
+/* below. */
+ /* 44790 1821 */ {0x00c0, 0x8804},
+ /* SSI slave addr */
+ /* 44815 1822 */ {0x0008, 0x8802},
+ /* 375 Khz SSI clock */
+ /* 44838 1823 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 44862 1824 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 44888 1825 */ {0x0008, 0x8802},
+ /* 375 Khz SSI clock */
+ /* 44913 1826 */ {0x0012, 0x8801},
+ /* SSI reg addr */
+ /* 44938 1827 */ {0x0080, 0x8800},
+ /* SSI data to write */
+ /* 44961 1828 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 44985 1829 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45009 1830 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45035 1831 */ {0x0008, 0x8802},
+ /* 375 Khz SSI clock */
+ /* 45060 1832 */ {0x0012, 0x8801},
+ /* SSI reg addr */
+ /* 45085 1833 */ {0x0000, 0x8800},
+ /* SSI data to write */
+ /* 45108 1834 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45132 1835 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45156 1836 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45182 1837 */ {0x0008, 0x8802},
+ /* 375 Khz SSI clock */
+ /* 45207 1838 */ {0x0011, 0x8801},
+ /* SSI reg addr */
+ /* 45232 1839 */ {0x0040, 0x8800},
+ /* SSI data to write */
+ /* 45255 1840 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45279 1841 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45303 1842 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45329 1843 */ {0x0008, 0x8802},
+ /* 45354 1844 */ {0x0013, 0x8801},
+ /* 45379 1845 */ {0x0000, 0x8800},
+ /* 45402 1846 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45426 1847 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45450 1848 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45476 1849 */ {0x0008, 0x8802},
+ /* 45501 1850 */ {0x0014, 0x8801},
+ /* 45526 1851 */ {0x0000, 0x8800},
+ /* 45549 1852 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45573 1853 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45597 1854 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45623 1855 */ {0x0008, 0x8802},
+ /* 45648 1856 */ {0x0015, 0x8801},
+ /* 45673 1857 */ {0x0001, 0x8800},
+ /* 45696 1858 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45720 1859 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45744 1860 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45770 1861 */ {0x0008, 0x8802},
+ /* 45795 1862 */ {0x0016, 0x8801},
+ /* 45820 1863 */ {0x0003, 0x8800},
+ /* 45843 1864 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45867 1865 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45891 1866 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45917 1867 */ {0x0008, 0x8802},
+ /* 45942 1868 */ {0x0017, 0x8801},
+ /* 45967 1869 */ {0x0036, 0x8800},
+ /* 45990 1870 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46014 1871 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46038 1872 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46064 1873 */ {0x0008, 0x8802},
+ /* 46089 1874 */ {0x0018, 0x8801},
+ /* 46114 1875 */ {0x00ec, 0x8800},
+ /* 46137 1876 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46161 1877 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46185 1878 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46211 1879 */ {0x0008, 0x8802},
+ /* 46236 1880 */ {0x001a, 0x8801},
+ /* 46261 1881 */ {0x0094, 0x8800},
+ /* 46284 1882 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46308 1883 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46332 1884 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46358 1885 */ {0x0008, 0x8802},
+ /* 46383 1886 */ {0x001b, 0x8801},
+ /* 46408 1887 */ {0x0000, 0x8800},
+ /* 46431 1888 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46455 1889 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46479 1890 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46505 1891 */ {0x0008, 0x8802},
+ /* 46530 1892 */ {0x0027, 0x8801},
+ /* 46555 1893 */ {0x00a2, 0x8800},
+ /* 46578 1894 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46602 1895 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46626 1896 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46652 1897 */ {0x0008, 0x8802},
+ /* 46677 1898 */ {0x0028, 0x8801},
+ /* 46702 1899 */ {0x0040, 0x8800},
+ /* 46725 1900 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46749 1901 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46773 1902 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46799 1903 */ {0x0008, 0x8802},
+ /* 46824 1904 */ {0x002a, 0x8801},
+ /* 46849 1905 */ {0x0084, 0x8800},
+ /* 46872 1906 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46896 1907 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46920 1908 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46946 1909 */ {0x0008, 0x8802},
+ /* 46971 1910 */ {0x002b, 0x8801},
+ /* 46996 1911 */ {0x00a8, 0x8800},
+ /* 47019 1912 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47043 1913 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47067 1914 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47093 1915 */ {0x0008, 0x8802},
+ /* 47118 1916 */ {0x002c, 0x8801},
+ /* 47143 1917 */ {0x00fe, 0x8800},
+ /* 47166 1918 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47190 1919 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47214 1920 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47240 1921 */ {0x0008, 0x8802},
+ /* 47265 1922 */ {0x002d, 0x8801},
+ /* 47290 1923 */ {0x0003, 0x8800},
+ /* 47313 1924 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47337 1925 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47361 1926 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47387 1927 */ {0x0008, 0x8802},
+ /* 47412 1928 */ {0x0038, 0x8801},
+ /* 47437 1929 */ {0x0083, 0x8800},
+ /* 47460 1930 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47484 1931 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47508 1932 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47534 1933 */ {0x0008, 0x8802},
+ /* 47559 1934 */ {0x0033, 0x8801},
+ /* 47584 1935 */ {0x0081, 0x8800},
+ /* 47607 1936 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47631 1937 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47655 1938 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47681 1939 */ {0x0008, 0x8802},
+ /* 47706 1940 */ {0x0034, 0x8801},
+ /* 47731 1941 */ {0x004a, 0x8800},
+ /* 47754 1942 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47778 1943 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47802 1944 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47828 1945 */ {0x0008, 0x8802},
+ /* 47853 1946 */ {0x0039, 0x8801},
+ /* 47878 1947 */ {0x0000, 0x8800},
+ /* 47901 1948 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47925 1949 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47949 1950 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47975 1951 */ {0x0008, 0x8802},
+ /* 48000 1952 */ {0x0010, 0x8801},
+ /* 48025 1953 */ {0x00a8, 0x8800},
+ /* 48048 1954 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48072 1955 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48096 1956 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 48122 1957 */ {0x0008, 0x8802},
+ /* 48147 1958 */ {0x0006, 0x8801},
+ /* 48172 1959 */ {0x0058, 0x8800},
+ /* 48195 1960 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48219 1961 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48243 1962 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 48269 1963 */ {0x0008, 0x8802},
+ /* 48294 1964 */ {0x0000, 0x8801},
+ /* 48319 1965 */ {0x0004, 0x8800},
+ /* 48342 1966 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48366 1967 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48390 1968 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 48416 1969 */ {0x0008, 0x8802},
+ /* 48441 1970 */ {0x0040, 0x8801},
+ /* 48466 1971 */ {0x0080, 0x8800},
+ /* 48489 1972 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48513 1973 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48537 1974 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 48563 1975 */ {0x0008, 0x8802},
+ /* 48588 1976 */ {0x0041, 0x8801},
+ /* 48613 1977 */ {0x000c, 0x8800},
+ /* 48636 1978 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48660 1979 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48684 1980 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 48710 1981 */ {0x0008, 0x8802},
+ /* 48735 1982 */ {0x0042, 0x8801},
+ /* 48760 1983 */ {0x000c, 0x8800},
+ /* 48783 1984 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48807 1985 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48831 1986 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 48857 1987 */ {0x0008, 0x8802},
+ /* 48882 1988 */ {0x0043, 0x8801},
+ /* 48907 1989 */ {0x0028, 0x8800},
+ /* 48930 1990 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48954 1991 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48978 1992 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49004 1993 */ {0x0008, 0x8802},
+ /* 49029 1994 */ {0x0044, 0x8801},
+ /* 49054 1995 */ {0x0080, 0x8800},
+ /* 49077 1996 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49101 1997 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49125 1998 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49151 1999 */ {0x0008, 0x8802},
+ /* 49176 2000 */ {0x0045, 0x8801},
+ /* 49201 2001 */ {0x0020, 0x8800},
+ /* 49224 2002 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49248 2003 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49272 2004 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49298 2005 */ {0x0008, 0x8802},
+ /* 49323 2006 */ {0x0046, 0x8801},
+ /* 49348 2007 */ {0x0020, 0x8800},
+ /* 49371 2008 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49395 2009 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49419 2010 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49445 2011 */ {0x0008, 0x8802},
+ /* 49470 2012 */ {0x0047, 0x8801},
+ /* 49495 2013 */ {0x0080, 0x8800},
+ /* 49518 2014 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49542 2015 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49566 2016 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49592 2017 */ {0x0008, 0x8802},
+ /* 49617 2018 */ {0x0048, 0x8801},
+ /* 49642 2019 */ {0x004c, 0x8800},
+ /* 49665 2020 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49689 2021 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49713 2022 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49739 2023 */ {0x0008, 0x8802},
+ /* 49764 2024 */ {0x0049, 0x8801},
+ /* 49789 2025 */ {0x0084, 0x8800},
+ /* 49812 2026 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49836 2027 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49860 2028 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49886 2029 */ {0x0008, 0x8802},
+ /* 49911 2030 */ {0x004a, 0x8801},
+ /* 49936 2031 */ {0x0084, 0x8800},
+ /* 49959 2032 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49983 2033 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 50007 2034 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 50033 2035 */ {0x0008, 0x8802},
+ /* 50058 2036 */ {0x004b, 0x8801},
+ /* 50083 2037 */ {0x0084, 0x8800},
+ /* 50106 2038 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* --------------------------------------- */
+ /* 50132 2039 */ {0x0012, 0x8700},
+ /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+ /* 50157 2040 */ {0x0000, 0x8701},
+ /* CKx1 clock delay adj */
+ /* 50182 2041 */ {0x0000, 0x8701},
+ /* CKx1 clock delay adj */
+ /* 50207 2042 */ {0x0001, 0x870c},
+ /* CKOx2 output */
+ /* --------------------------------------- */
+ /* 50232 2043 */ {0x0080, 0x8600},
+ /* Line memory read counter (L) */
+ /* 50257 2044 */ {0x0001, 0x8606},
+ /* reserved */
+ /* 50282 2045 */ {0x0064, 0x8607},
+ /* Line memory read counter (H) 0x6480=25,728 */
+ /* 50307 2046 */ {0x002a, 0x8601},
+ /* CDSP sharp interpolation mode,
+ * line sel for color sep, edge enhance enab */
+ /* 50332 2047 */ {0x0000, 0x8602},
+ /* optical black level for user settng = 0 */
+ /* 50357 2048 */ {0x0080, 0x8600},
+ /* Line memory read counter (L) */
+ /* 50382 2049 */ {0x000a, 0x8603},
+ /* optical black level calc mode: auto; optical black offset = 10 */
+ /* 50407 2050 */ {0x00df, 0x865b},
+ /* Horiz offset for valid pixels (L)=0xdf */
+ /* 50432 2051 */ {0x0012, 0x865c},
+ /* Vert offset for valid lines (L)=0x12 */
+
+/* The following two lines seem to be the "wrong" resolution. */
+/* But perhaps these indicate the actual size of the sensor */
+/* rather than the size of the current video mode. */
+ /* 50457 2052 */ {0x0058, 0x865d},
+ /* Horiz valid pixels (*4) (L) = 352 */
+ /* 50482 2053 */ {0x0048, 0x865e},
+ /* Vert valid lines (*4) (L) = 288 */
+
+ /* 50507 2054 */ {0x0015, 0x8608},
+ /* A11 Coef ... */
+ /* 50532 2055 */ {0x0030, 0x8609},
+ /* 50557 2056 */ {0x00fb, 0x860a},
+ /* 50582 2057 */ {0x003e, 0x860b},
+ /* 50607 2058 */ {0x00ce, 0x860c},
+ /* 50632 2059 */ {0x00f4, 0x860d},
+ /* 50657 2060 */ {0x00eb, 0x860e},
+ /* 50682 2061 */ {0x00dc, 0x860f},
+ /* 50707 2062 */ {0x0039, 0x8610},
+ /* 50732 2063 */ {0x0001, 0x8611},
+ /* R offset for white balance ... */
+ /* 50757 2064 */ {0x0000, 0x8612},
+ /* 50782 2065 */ {0x0001, 0x8613},
+ /* 50807 2066 */ {0x0000, 0x8614},
+ /* 50832 2067 */ {0x005b, 0x8651},
+ /* R gain for white balance ... */
+ /* 50857 2068 */ {0x0040, 0x8652},
+ /* 50882 2069 */ {0x0060, 0x8653},
+ /* 50907 2070 */ {0x0040, 0x8654},
+ /* 50932 2071 */ {0x0000, 0x8655},
+ /* 50957 2072 */ {0x0001, 0x863f},
+ /* Fixed gamma correction enable, USB control,
+ * lum filter disable, lum noise clip disable */
+ /* 50982 2073 */ {0x00a1, 0x8656},
+ /* Window1 size 256x256, Windows2 size 64x64,
+ * gamma look-up disable, new edge enhancement enable */
+ /* 51007 2074 */ {0x0018, 0x8657},
+ /* Edge gain high thresh */
+ /* 51032 2075 */ {0x0020, 0x8658},
+ /* Edge gain low thresh */
+ /* 51057 2076 */ {0x000a, 0x8659},
+ /* Edge bandwidth high threshold */
+ /* 51082 2077 */ {0x0005, 0x865a},
+ /* Edge bandwidth low threshold */
+ /* -------------------------------- */
+ /* 51107 2078 */ {0x0030, 0x8112},
+ /* Video drop enable, ISO streaming enable */
+ /* 51130 2079 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 51154 2080 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 51180 2081 */ {0xa908, 0x8802},
+ /* 51205 2082 */ {0x0034, 0x8801},
+ /* SSI reg addr */
+ /* 51230 2083 */ {0x00ca, 0x8800},
+ /* SSI data to write */
+ /* 51253 2084 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 51277 2085 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 51301 2086 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 51327 2087 */ {0x1f08, 0x8802},
+ /* 51352 2088 */ {0x0006, 0x8801},
+ /* 51377 2089 */ {0x0080, 0x8800},
+ /* 51400 2090 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+
+/* ----- Read back coefs we wrote earlier. */
+ /* 51424 2091 */ /* READ { 0, 0x0000, 0x8608 } -> 0000: 15 */
+ /* 51448 2092 */ /* READ { 0, 0x0000, 0x8609 } -> 0000: 30 */
+ /* 51472 2093 */ /* READ { 0, 0x0000, 0x860a } -> 0000: fb */
+ /* 51496 2094 */ /* READ { 0, 0x0000, 0x860b } -> 0000: 3e */
+ /* 51520 2095 */ /* READ { 0, 0x0000, 0x860c } -> 0000: ce */
+ /* 51544 2096 */ /* READ { 0, 0x0000, 0x860d } -> 0000: f4 */
+ /* 51568 2097 */ /* READ { 0, 0x0000, 0x860e } -> 0000: eb */
+ /* 51592 2098 */ /* READ { 0, 0x0000, 0x860f } -> 0000: dc */
+ /* 51616 2099 */ /* READ { 0, 0x0000, 0x8610 } -> 0000: 39 */
+ /* 51640 2100 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 51664 2101 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 51690 2102 */ {0xb008, 0x8802},
+ /* 51715 2103 */ {0x0006, 0x8801},
+ /* 51740 2104 */ {0x007d, 0x8800},
+ /* 51763 2105 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+
+
+ /* This chunk is seemingly redundant with */
+ /* earlier commands (A11 Coef...), but if I disable it, */
+ /* the image appears too dark. Maybe there was some kind of */
+ /* reset since the earlier commands, so this is necessary again. */
+ /* 51789 2106 */ {0x0015, 0x8608},
+ /* 51814 2107 */ {0x0030, 0x8609},
+ /* 51839 2108 */ {0xfffb, 0x860a},
+ /* 51864 2109 */ {0x003e, 0x860b},
+ /* 51889 2110 */ {0xffce, 0x860c},
+ /* 51914 2111 */ {0xfff4, 0x860d},
+ /* 51939 2112 */ {0xffeb, 0x860e},
+ /* 51964 2113 */ {0xffdc, 0x860f},
+ /* 51989 2114 */ {0x0039, 0x8610},
+ /* 52014 2115 */ {0x0018, 0x8657},
+
+ /* 52039 2116 */ {0x0000, 0x8508},
+ /* Disable compression. */
+ /* Previous line was:
+ * 52039 2116 * { 0, 0x0021, 0x8508 }, * Enable compression. */
+ /* 52064 2117 */ {0x0032, 0x850b},
+ /* compression stuff */
+ /* 52089 2118 */ {0x0003, 0x8509},
+ /* compression stuff */
+ /* 52114 2119 */ {0x0011, 0x850a},
+ /* compression stuff */
+ /* 52139 2120 */ {0x0021, 0x850d},
+ /* compression stuff */
+ /* 52164 2121 */ {0x0010, 0x850c},
+ /* compression stuff */
+ /* 52189 2122 */ {0x0003, 0x8500},
+ /* *** Video mode: 160x120 */
+ /* 52214 2123 */ {0x0001, 0x8501},
+ /* Hardware-dominated snap control */
+ /* 52239 2124 */ {0x0061, 0x8656},
+ /* Window1 size 128x128, Windows2 size 128x128,
+ * gamma look-up disable, new edge enhancement enable */
+ /* 52264 2125 */ {0x0018, 0x8617},
+ /* Window1 start X (*2) */
+ /* 52289 2126 */ {0x0008, 0x8618},
+ /* Window1 start Y (*2) */
+ /* 52314 2127 */ {0x0061, 0x8656},
+ /* Window1 size 128x128, Windows2 size 128x128,
+ * gamma look-up disable, new edge enhancement enable */
+ /* 52339 2128 */ {0x0058, 0x8619},
+ /* Window2 start X (*2) */
+ /* 52364 2129 */ {0x0008, 0x861a},
+ /* Window2 start Y (*2) */
+ /* 52389 2130 */ {0x00ff, 0x8615},
+ /* High lum thresh for white balance */
+ /* 52414 2131 */ {0x0000, 0x8616},
+ /* Low lum thresh for white balance */
+ /* 52439 2132 */ {0x0012, 0x8700},
+ /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+ /* 52464 2133 */ {0x0012, 0x8700},
+ /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+ /* 52487 2134 */ /* READ { 0, 0x0000, 0x8656 } -> 0000: 61 */
+ /* 52513 2135 */ {0x0028, 0x8802},
+ /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+ /* 52536 2136 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 52560 2137 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28 */
+ /* 52586 2138 */ {0x1f28, 0x8802},
+ /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+ /* 52611 2139 */ {0x0010, 0x8801},
+ /* SSI reg addr */
+ /* 52636 2140 */ {0x003e, 0x8800},
+ /* SSI data to write */
+ /* 52659 2141 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 52685 2142 */ {0x0028, 0x8802},
+ /* 52708 2143 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 52732 2144 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28 */
+ /* 52758 2145 */ {0x1f28, 0x8802},
+ /* 52783 2146 */ {0x0000, 0x8801},
+ /* 52808 2147 */ {0x001f, 0x8800},
+ /* 52831 2148 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 52857 2149 */ {0x0001, 0x8602},
+ /* optical black level for user settning = 1 */
+
+ /* Original: */
+ /* 52882 2150 */ {0x0023, 0x8700},
+ /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */
+ /* 52907 2151 */ {0x000f, 0x8602},
+ /* optical black level for user settning = 15 */
+
+ /* 52932 2152 */ {0x0028, 0x8802},
+ /* 52955 2153 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 52979 2154 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28 */
+ /* 53005 2155 */ {0x1f28, 0x8802},
+ /* 53030 2156 */ {0x0010, 0x8801},
+ /* 53055 2157 */ {0x007b, 0x8800},
+ /* 53078 2158 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 53104 2159 */ {0x002f, 0x8651},
+ /* R gain for white balance ... */
+ /* 53129 2160 */ {0x0080, 0x8653},
+ /* 53152 2161 */ /* READ { 0, 0x0000, 0x8655 } -> 0000: 00 */
+ /* 53178 2162 */ {0x0000, 0x8655},
+
+ /* 53203 2163 */ {0x0030, 0x8112},
+ /* Video drop enable, ISO streaming enable */
+ /* 53228 2164 */ {0x0020, 0x8112},
+ /* Video drop enable, ISO streaming disable */
+ /* 53252 2165 */
+ /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */
+ {}
+};
+
+
+/*
+ * Initialization data for Intel EasyPC Camera CS110
+ */
+static const __u16 spca508cs110_init_data[][3] = {
+ {0x0000, 0x870b}, /* Reset CTL3 */
+ {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
+ {0x0000, 0x8111}, /* Normal operation on reset */
+ {0x0090, 0x8110},
+ /* External Clock 2x & Synchronous Serial Interface Output */
+ {0x0020, 0x8112}, /* Video Drop packet enable */
+ {0x0000, 0x8114}, /* Software GPIO output data */
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0003, 0x8114},
+
+ /* Initial sequence Synchronous Serial Interface */
+ {0x000f, 0x8402}, /* Memory bank Address */
+ {0x0000, 0x8403}, /* Memory bank Address */
+ {0x00ba, 0x8804}, /* SSI Slave address */
+ {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */
+ {0x0010, 0x8802}, /* 93.75kHz SSI Clock two DataByte */
+
+ {0x0001, 0x8801},
+ {0x000a, 0x8805},/* a - NWG: Dunno what this is about */
+ {0x0000, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0002, 0x8801},
+ {0x0000, 0x8805},
+ {0x0000, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0003, 0x8801},
+ {0x0027, 0x8805},
+ {0x0001, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0004, 0x8801},
+ {0x0065, 0x8805},
+ {0x0001, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0005, 0x8801},
+ {0x0003, 0x8805},
+ {0x0000, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0006, 0x8801},
+ {0x001c, 0x8805},
+ {0x0000, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0007, 0x8801},
+ {0x002a, 0x8805},
+ {0x0000, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0002, 0x8704}, /* External input CKIx1 */
+ {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
+ {0x009a, 0x8600}, /* Line memory Read Counter (L) */
+ {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */
+ {0x0003, 0x865c}, /* 3 Vertical Offset for Valid Lines(L) */
+ {0x0058, 0x865d}, /* 58 Horizontal Valid Pixel Window(L) */
+
+ {0x0006, 0x8660}, /* Nibble data + input order */
+
+ {0x000a, 0x8602}, /* Optical black level set to 0x0a */
+/* 1945 */ {0x0000, 0x8603}, /* Optical black level Offset */
+
+/* 1962 * {0, 0x0000, 0x8611}, * 0 R Offset for white Balance */
+/* 1963 * {0, 0x0000, 0x8612}, * 1 Gr Offset for white Balance */
+/* 1964 * {0, 0x0000, 0x8613}, * 1f B Offset for white Balance */
+/* 1965 * {0, 0x0000, 0x8614}, * f0 Gb Offset for white Balance */
+
+ {0x0040, 0x8651}, /* 2b BLUE gain for white balance good at all 60 */
+ {0x0030, 0x8652}, /* 41 Gr Gain for white Balance (L) */
+ {0x0035, 0x8653}, /* 26 RED gain for white balance */
+ {0x0035, 0x8654}, /* 40Gb Gain for white Balance (L) */
+ {0x0041, 0x863f},
+ /* Fixed Gamma correction enabled (makes colours look better) */
+
+/* 2422 */ {0x0000, 0x8655},
+ /* High bits for white balance*****brightness control*** */
+ {}
+};
+
+static const __u16 spca508_sightcam_init_data[][3] = {
+/* This line seems to setup the frame/canvas */
+ /*368 */ {0x000f, 0x8402},
+
+/* Theese 6 lines are needed to startup the webcam */
+ /*398 */ {0x0090, 0x8110},
+ /*399 */ {0x0001, 0x8114},
+ /*400 */ {0x0001, 0x8114},
+ /*401 */ {0x0001, 0x8114},
+ /*402 */ {0x0003, 0x8114},
+ /*403 */ {0x0080, 0x8804},
+
+/* This part seems to make the pictures darker? (autobrightness?) */
+ /*436 */ {0x0001, 0x8801},
+ /*437 */ {0x0004, 0x8800},
+ /*439 */ {0x0003, 0x8801},
+ /*440 */ {0x00e0, 0x8800},
+ /*442 */ {0x0004, 0x8801},
+ /*443 */ {0x00b4, 0x8800},
+ /*445 */ {0x0005, 0x8801},
+ /*446 */ {0x0000, 0x8800},
+
+ /*448 */ {0x0006, 0x8801},
+ /*449 */ {0x00e0, 0x8800},
+ /*451 */ {0x0007, 0x8801},
+ /*452 */ {0x000c, 0x8800},
+
+/* This section is just needed, it probably
+ * does something like the previous section,
+ * but the cam won't start if it's not included.
+ */
+ /*484 */ {0x0014, 0x8801},
+ /*485 */ {0x0008, 0x8800},
+ /*487 */ {0x0015, 0x8801},
+ /*488 */ {0x0067, 0x8800},
+ /*490 */ {0x0016, 0x8801},
+ /*491 */ {0x0000, 0x8800},
+ /*493 */ {0x0017, 0x8801},
+ /*494 */ {0x0020, 0x8800},
+ /*496 */ {0x0018, 0x8801},
+ /*497 */ {0x0044, 0x8800},
+
+/* Makes the picture darker - and the
+ * cam won't start if not included
+ */
+ /*505 */ {0x001e, 0x8801},
+ /*506 */ {0x00ea, 0x8800},
+ /*508 */ {0x001f, 0x8801},
+ /*509 */ {0x0001, 0x8800},
+ /*511 */ {0x0003, 0x8801},
+ /*512 */ {0x00e0, 0x8800},
+
+/* seems to place the colors ontop of each other #1 */
+ /*517 */ {0x0006, 0x8704},
+ /*518 */ {0x0001, 0x870c},
+ /*519 */ {0x0016, 0x8600},
+ /*520 */ {0x0002, 0x8606},
+
+/* if not included the pictures becomes _very_ dark */
+ /*521 */ {0x0064, 0x8607},
+ /*522 */ {0x003a, 0x8601},
+ /*523 */ {0x0000, 0x8602},
+
+/* seems to place the colors ontop of each other #2 */
+ /*524 */ {0x0016, 0x8600},
+ /*525 */ {0x0018, 0x8617},
+ /*526 */ {0x0008, 0x8618},
+ /*527 */ {0x00a1, 0x8656},
+
+/* webcam won't start if not included */
+ /*528 */ {0x0007, 0x865b},
+ /*529 */ {0x0001, 0x865c},
+ /*530 */ {0x0058, 0x865d},
+ /*531 */ {0x0048, 0x865e},
+
+/* adjusts the colors */
+ /*541 */ {0x0049, 0x8651},
+ /*542 */ {0x0040, 0x8652},
+ /*543 */ {0x004c, 0x8653},
+ /*544 */ {0x0040, 0x8654},
+ {}
+};
+
+static const __u16 spca508_sightcam2_init_data[][3] = {
+/* 35 */ {0x0020, 0x8112},
+
+/* 36 */ {0x000f, 0x8402},
+/* 37 */ {0x0000, 0x8403},
+
+/* 38 */ {0x0008, 0x8201},
+/* 39 */ {0x0008, 0x8200},
+/* 40 */ {0x0001, 0x8200},
+/* 43 */ {0x0009, 0x8201},
+/* 44 */ {0x0008, 0x8200},
+/* 45 */ {0x0001, 0x8200},
+/* 48 */ {0x000a, 0x8201},
+/* 49 */ {0x0008, 0x8200},
+/* 50 */ {0x0001, 0x8200},
+/* 53 */ {0x000b, 0x8201},
+/* 54 */ {0x0008, 0x8200},
+/* 55 */ {0x0001, 0x8200},
+/* 58 */ {0x000c, 0x8201},
+/* 59 */ {0x0008, 0x8200},
+/* 60 */ {0x0001, 0x8200},
+/* 63 */ {0x000d, 0x8201},
+/* 64 */ {0x0008, 0x8200},
+/* 65 */ {0x0001, 0x8200},
+/* 68 */ {0x000e, 0x8201},
+/* 69 */ {0x0008, 0x8200},
+/* 70 */ {0x0001, 0x8200},
+/* 73 */ {0x0007, 0x8201},
+/* 74 */ {0x0008, 0x8200},
+/* 75 */ {0x0001, 0x8200},
+/* 78 */ {0x000f, 0x8201},
+/* 79 */ {0x0008, 0x8200},
+/* 80 */ {0x0001, 0x8200},
+
+/* 84 */ {0x0018, 0x8660},
+/* 85 */ {0x0010, 0x8201},
+
+/* 86 */ {0x0008, 0x8200},
+/* 87 */ {0x0001, 0x8200},
+/* 90 */ {0x0011, 0x8201},
+/* 91 */ {0x0008, 0x8200},
+/* 92 */ {0x0001, 0x8200},
+
+/* 95 */ {0x0000, 0x86b0},
+/* 96 */ {0x0034, 0x86b1},
+/* 97 */ {0x0000, 0x86b2},
+/* 98 */ {0x0049, 0x86b3},
+/* 99 */ {0x0000, 0x86b4},
+/* 100 */ {0x0000, 0x86b4},
+
+/* 101 */ {0x0012, 0x8201},
+/* 102 */ {0x0008, 0x8200},
+/* 103 */ {0x0001, 0x8200},
+/* 106 */ {0x0013, 0x8201},
+/* 107 */ {0x0008, 0x8200},
+/* 108 */ {0x0001, 0x8200},
+
+/* 111 */ {0x0001, 0x86b0},
+/* 112 */ {0x00aa, 0x86b1},
+/* 113 */ {0x0000, 0x86b2},
+/* 114 */ {0x00e4, 0x86b3},
+/* 115 */ {0x0000, 0x86b4},
+/* 116 */ {0x0000, 0x86b4},
+
+/* 118 */ {0x0018, 0x8660},
+
+/* 119 */ {0x0090, 0x8110},
+/* 120 */ {0x0001, 0x8114},
+/* 121 */ {0x0001, 0x8114},
+/* 122 */ {0x0001, 0x8114},
+/* 123 */ {0x0003, 0x8114},
+
+/* 124 */ {0x0080, 0x8804},
+/* 157 */ {0x0003, 0x8801},
+/* 158 */ {0x0012, 0x8800},
+/* 160 */ {0x0004, 0x8801},
+/* 161 */ {0x0005, 0x8800},
+/* 163 */ {0x0005, 0x8801},
+/* 164 */ {0x0000, 0x8800},
+/* 166 */ {0x0006, 0x8801},
+/* 167 */ {0x0000, 0x8800},
+/* 169 */ {0x0007, 0x8801},
+/* 170 */ {0x0000, 0x8800},
+/* 172 */ {0x0008, 0x8801},
+/* 173 */ {0x0005, 0x8800},
+/* 175 */ {0x000a, 0x8700},
+/* 176 */ {0x000e, 0x8801},
+/* 177 */ {0x0004, 0x8800},
+/* 179 */ {0x0005, 0x8801},
+/* 180 */ {0x0047, 0x8800},
+/* 182 */ {0x0006, 0x8801},
+/* 183 */ {0x0000, 0x8800},
+/* 185 */ {0x0007, 0x8801},
+/* 186 */ {0x00c0, 0x8800},
+/* 188 */ {0x0008, 0x8801},
+/* 189 */ {0x0003, 0x8800},
+/* 191 */ {0x0013, 0x8801},
+/* 192 */ {0x0001, 0x8800},
+/* 194 */ {0x0009, 0x8801},
+/* 195 */ {0x0000, 0x8800},
+/* 197 */ {0x000a, 0x8801},
+/* 198 */ {0x0000, 0x8800},
+/* 200 */ {0x000b, 0x8801},
+/* 201 */ {0x0000, 0x8800},
+/* 203 */ {0x000c, 0x8801},
+/* 204 */ {0x0000, 0x8800},
+/* 206 */ {0x000e, 0x8801},
+/* 207 */ {0x0004, 0x8800},
+/* 209 */ {0x000f, 0x8801},
+/* 210 */ {0x0000, 0x8800},
+/* 212 */ {0x0010, 0x8801},
+/* 213 */ {0x0006, 0x8800},
+/* 215 */ {0x0011, 0x8801},
+/* 216 */ {0x0006, 0x8800},
+/* 218 */ {0x0012, 0x8801},
+/* 219 */ {0x0000, 0x8800},
+/* 221 */ {0x0013, 0x8801},
+/* 222 */ {0x0001, 0x8800},
+
+/* 224 */ {0x000a, 0x8700},
+/* 225 */ {0x0000, 0x8702},
+/* 226 */ {0x0000, 0x8703},
+/* 227 */ {0x00c2, 0x8704},
+/* 228 */ {0x0001, 0x870c},
+
+/* 229 */ {0x0044, 0x8600},
+/* 230 */ {0x0002, 0x8606},
+/* 231 */ {0x0064, 0x8607},
+/* 232 */ {0x003a, 0x8601},
+/* 233 */ {0x0008, 0x8602},
+/* 234 */ {0x0044, 0x8600},
+/* 235 */ {0x0018, 0x8617},
+/* 236 */ {0x0008, 0x8618},
+/* 237 */ {0x00a1, 0x8656},
+/* 238 */ {0x0004, 0x865b},
+/* 239 */ {0x0002, 0x865c},
+/* 240 */ {0x0058, 0x865d},
+/* 241 */ {0x0048, 0x865e},
+/* 242 */ {0x0012, 0x8608},
+/* 243 */ {0x002c, 0x8609},
+/* 244 */ {0x0002, 0x860a},
+/* 245 */ {0x002c, 0x860b},
+/* 246 */ {0x00db, 0x860c},
+/* 247 */ {0x00f9, 0x860d},
+/* 248 */ {0x00f1, 0x860e},
+/* 249 */ {0x00e3, 0x860f},
+/* 250 */ {0x002c, 0x8610},
+/* 251 */ {0x006c, 0x8651},
+/* 252 */ {0x0041, 0x8652},
+/* 253 */ {0x0059, 0x8653},
+/* 254 */ {0x0040, 0x8654},
+/* 255 */ {0x00fa, 0x8611},
+/* 256 */ {0x00ff, 0x8612},
+/* 257 */ {0x00f8, 0x8613},
+/* 258 */ {0x0000, 0x8614},
+/* 259 */ {0x0001, 0x863f},
+/* 260 */ {0x0000, 0x8640},
+/* 261 */ {0x0026, 0x8641},
+/* 262 */ {0x0045, 0x8642},
+/* 263 */ {0x0060, 0x8643},
+/* 264 */ {0x0075, 0x8644},
+/* 265 */ {0x0088, 0x8645},
+/* 266 */ {0x009b, 0x8646},
+/* 267 */ {0x00b0, 0x8647},
+/* 268 */ {0x00c5, 0x8648},
+/* 269 */ {0x00d2, 0x8649},
+/* 270 */ {0x00dc, 0x864a},
+/* 271 */ {0x00e5, 0x864b},
+/* 272 */ {0x00eb, 0x864c},
+/* 273 */ {0x00f0, 0x864d},
+/* 274 */ {0x00f6, 0x864e},
+/* 275 */ {0x00fa, 0x864f},
+/* 276 */ {0x00ff, 0x8650},
+/* 277 */ {0x0060, 0x8657},
+/* 278 */ {0x0010, 0x8658},
+/* 279 */ {0x0018, 0x8659},
+/* 280 */ {0x0005, 0x865a},
+/* 281 */ {0x0018, 0x8660},
+/* 282 */ {0x0003, 0x8509},
+/* 283 */ {0x0011, 0x850a},
+/* 284 */ {0x0032, 0x850b},
+/* 285 */ {0x0010, 0x850c},
+/* 286 */ {0x0021, 0x850d},
+/* 287 */ {0x0001, 0x8500},
+/* 288 */ {0x0000, 0x8508},
+/* 289 */ {0x0012, 0x8608},
+/* 290 */ {0x002c, 0x8609},
+/* 291 */ {0x0002, 0x860a},
+/* 292 */ {0x0039, 0x860b},
+/* 293 */ {0x00d0, 0x860c},
+/* 294 */ {0x00f7, 0x860d},
+/* 295 */ {0x00ed, 0x860e},
+/* 296 */ {0x00db, 0x860f},
+/* 297 */ {0x0039, 0x8610},
+/* 298 */ {0x0012, 0x8657},
+/* 299 */ {0x000c, 0x8619},
+/* 300 */ {0x0004, 0x861a},
+/* 301 */ {0x00a1, 0x8656},
+/* 302 */ {0x00c8, 0x8615},
+/* 303 */ {0x0032, 0x8616},
+
+/* 306 */ {0x0030, 0x8112},
+/* 313 */ {0x0020, 0x8112},
+/* 314 */ {0x0020, 0x8112},
+/* 315 */ {0x000f, 0x8402},
+/* 316 */ {0x0000, 0x8403},
+
+/* 317 */ {0x0090, 0x8110},
+/* 318 */ {0x0001, 0x8114},
+/* 319 */ {0x0001, 0x8114},
+/* 320 */ {0x0001, 0x8114},
+/* 321 */ {0x0003, 0x8114},
+/* 322 */ {0x0080, 0x8804},
+
+/* 355 */ {0x0003, 0x8801},
+/* 356 */ {0x0012, 0x8800},
+/* 358 */ {0x0004, 0x8801},
+/* 359 */ {0x0005, 0x8800},
+/* 361 */ {0x0005, 0x8801},
+/* 362 */ {0x0047, 0x8800},
+/* 364 */ {0x0006, 0x8801},
+/* 365 */ {0x0000, 0x8800},
+/* 367 */ {0x0007, 0x8801},
+/* 368 */ {0x00c0, 0x8800},
+/* 370 */ {0x0008, 0x8801},
+/* 371 */ {0x0003, 0x8800},
+/* 373 */ {0x000a, 0x8700},
+/* 374 */ {0x000e, 0x8801},
+/* 375 */ {0x0004, 0x8800},
+/* 377 */ {0x0005, 0x8801},
+/* 378 */ {0x0047, 0x8800},
+/* 380 */ {0x0006, 0x8801},
+/* 381 */ {0x0000, 0x8800},
+/* 383 */ {0x0007, 0x8801},
+/* 384 */ {0x00c0, 0x8800},
+/* 386 */ {0x0008, 0x8801},
+/* 387 */ {0x0003, 0x8800},
+/* 389 */ {0x0013, 0x8801},
+/* 390 */ {0x0001, 0x8800},
+/* 392 */ {0x0009, 0x8801},
+/* 393 */ {0x0000, 0x8800},
+/* 395 */ {0x000a, 0x8801},
+/* 396 */ {0x0000, 0x8800},
+/* 398 */ {0x000b, 0x8801},
+/* 399 */ {0x0000, 0x8800},
+/* 401 */ {0x000c, 0x8801},
+/* 402 */ {0x0000, 0x8800},
+/* 404 */ {0x000e, 0x8801},
+/* 405 */ {0x0004, 0x8800},
+/* 407 */ {0x000f, 0x8801},
+/* 408 */ {0x0000, 0x8800},
+/* 410 */ {0x0010, 0x8801},
+/* 411 */ {0x0006, 0x8800},
+/* 413 */ {0x0011, 0x8801},
+/* 414 */ {0x0006, 0x8800},
+/* 416 */ {0x0012, 0x8801},
+/* 417 */ {0x0000, 0x8800},
+/* 419 */ {0x0013, 0x8801},
+/* 420 */ {0x0001, 0x8800},
+/* 422 */ {0x000a, 0x8700},
+/* 423 */ {0x0000, 0x8702},
+/* 424 */ {0x0000, 0x8703},
+/* 425 */ {0x00c2, 0x8704},
+/* 426 */ {0x0001, 0x870c},
+/* 427 */ {0x0044, 0x8600},
+/* 428 */ {0x0002, 0x8606},
+/* 429 */ {0x0064, 0x8607},
+/* 430 */ {0x003a, 0x8601},
+/* 431 */ {0x0008, 0x8602},
+/* 432 */ {0x0044, 0x8600},
+/* 433 */ {0x0018, 0x8617},
+/* 434 */ {0x0008, 0x8618},
+/* 435 */ {0x00a1, 0x8656},
+/* 436 */ {0x0004, 0x865b},
+/* 437 */ {0x0002, 0x865c},
+/* 438 */ {0x0058, 0x865d},
+/* 439 */ {0x0048, 0x865e},
+/* 440 */ {0x0012, 0x8608},
+/* 441 */ {0x002c, 0x8609},
+/* 442 */ {0x0002, 0x860a},
+/* 443 */ {0x002c, 0x860b},
+/* 444 */ {0x00db, 0x860c},
+/* 445 */ {0x00f9, 0x860d},
+/* 446 */ {0x00f1, 0x860e},
+/* 447 */ {0x00e3, 0x860f},
+/* 448 */ {0x002c, 0x8610},
+/* 449 */ {0x006c, 0x8651},
+/* 450 */ {0x0041, 0x8652},
+/* 451 */ {0x0059, 0x8653},
+/* 452 */ {0x0040, 0x8654},
+/* 453 */ {0x00fa, 0x8611},
+/* 454 */ {0x00ff, 0x8612},
+/* 455 */ {0x00f8, 0x8613},
+/* 456 */ {0x0000, 0x8614},
+/* 457 */ {0x0001, 0x863f},
+/* 458 */ {0x0000, 0x8640},
+/* 459 */ {0x0026, 0x8641},
+/* 460 */ {0x0045, 0x8642},
+/* 461 */ {0x0060, 0x8643},
+/* 462 */ {0x0075, 0x8644},
+/* 463 */ {0x0088, 0x8645},
+/* 464 */ {0x009b, 0x8646},
+/* 465 */ {0x00b0, 0x8647},
+/* 466 */ {0x00c5, 0x8648},
+/* 467 */ {0x00d2, 0x8649},
+/* 468 */ {0x00dc, 0x864a},
+/* 469 */ {0x00e5, 0x864b},
+/* 470 */ {0x00eb, 0x864c},
+/* 471 */ {0x00f0, 0x864d},
+/* 472 */ {0x00f6, 0x864e},
+/* 473 */ {0x00fa, 0x864f},
+/* 474 */ {0x00ff, 0x8650},
+/* 475 */ {0x0060, 0x8657},
+/* 476 */ {0x0010, 0x8658},
+/* 477 */ {0x0018, 0x8659},
+/* 478 */ {0x0005, 0x865a},
+/* 479 */ {0x0018, 0x8660},
+/* 480 */ {0x0003, 0x8509},
+/* 481 */ {0x0011, 0x850a},
+/* 482 */ {0x0032, 0x850b},
+/* 483 */ {0x0010, 0x850c},
+/* 484 */ {0x0021, 0x850d},
+/* 485 */ {0x0001, 0x8500},
+/* 486 */ {0x0000, 0x8508},
+
+/* 487 */ {0x0012, 0x8608},
+/* 488 */ {0x002c, 0x8609},
+/* 489 */ {0x0002, 0x860a},
+/* 490 */ {0x0039, 0x860b},
+/* 491 */ {0x00d0, 0x860c},
+/* 492 */ {0x00f7, 0x860d},
+/* 493 */ {0x00ed, 0x860e},
+/* 494 */ {0x00db, 0x860f},
+/* 495 */ {0x0039, 0x8610},
+/* 496 */ {0x0012, 0x8657},
+/* 497 */ {0x0064, 0x8619},
+
+/* This line starts it all, it is not needed here */
+/* since it has been build into the driver */
+/* jfm: don't start now */
+/* 590 * {0x0030, 0x8112}, */
+ {}
+};
+
+/*
+ * Initialization data for Creative Webcam Vista
+ */
+static const __u16 spca508_vista_init_data[][3] = {
+ {0x0008, 0x8200}, /* Clear register */
+ {0x0000, 0x870b}, /* Reset CTL3 */
+ {0x0020, 0x8112}, /* Video Drop packet enable */
+ {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
+ {0x0000, 0x8110}, /* Disable everything */
+ {0x0000, 0x8114}, /* Software GPIO output data */
+ {0x0000, 0x8114},
+
+ {0x0003, 0x8111},
+ {0x0000, 0x8111},
+ {0x0090, 0x8110}, /* Enable: SSI output, External 2X clock output */
+ {0x0020, 0x8112},
+ {0x0000, 0x8114},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0003, 0x8114},
+
+ {0x000f, 0x8402}, /* Memory bank Address */
+ {0x0000, 0x8403}, /* Memory bank Address */
+ {0x00ba, 0x8804}, /* SSI Slave address */
+ {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802}, /* Will write 2 bytes (DATA1+DATA2) */
+ {0x0020, 0x8801}, /* Register address for SSI read/write */
+ {0x0044, 0x8805}, /* DATA2 */
+ {0x0004, 0x8800}, /* DATA1 -> write triggered */
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0009, 0x8801},
+ {0x0042, 0x8805},
+ {0x0001, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x003c, 0x8801},
+ {0x0001, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0001, 0x8801},
+ {0x000a, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0002, 0x8801},
+ {0x0000, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0003, 0x8801},
+ {0x0027, 0x8805},
+ {0x0001, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0004, 0x8801},
+ {0x0065, 0x8805},
+ {0x0001, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0005, 0x8801},
+ {0x0003, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0006, 0x8801},
+ {0x001c, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0007, 0x8801},
+ {0x002a, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x000e, 0x8801},
+ {0x0000, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0028, 0x8801},
+ {0x002e, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0039, 0x8801},
+ {0x0013, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x003b, 0x8801},
+ {0x000c, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0035, 0x8801},
+ {0x0028, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0009, 0x8801},
+ {0x0042, 0x8805},
+ {0x0001, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ {0x0050, 0x8703},
+ {0x0002, 0x8704}, /* External input CKIx1 */
+ {0x0001, 0x870C}, /* Select CKOx2 output */
+ {0x009A, 0x8600}, /* Line memory Read Counter (L) */
+ {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
+ {0x0023, 0x8601},
+ {0x0010, 0x8602},
+ {0x000A, 0x8603},
+ {0x009A, 0x8600},
+ {0x0001, 0x865B}, /* 1 Horizontal Offset for Valid Pixel(L) */
+ {0x0003, 0x865C}, /* Vertical offset for valid lines (L) */
+ {0x0058, 0x865D}, /* Horizontal valid pixels window (L) */
+ {0x0048, 0x865E}, /* Vertical valid lines window (L) */
+ {0x0000, 0x865F},
+
+ {0x0006, 0x8660},
+ /* Enable nibble data input, select nibble input order */
+
+ {0x0013, 0x8608}, /* A11 Coeficients for color correction */
+ {0x0028, 0x8609},
+ /* Note: these values are confirmed at the end of array */
+ {0x0005, 0x860A}, /* ... */
+ {0x0025, 0x860B},
+ {0x00E1, 0x860C},
+ {0x00FA, 0x860D},
+ {0x00F4, 0x860E},
+ {0x00E8, 0x860F},
+ {0x0025, 0x8610}, /* A33 Coef. */
+ {0x00FC, 0x8611}, /* White balance offset: R */
+ {0x0001, 0x8612}, /* White balance offset: Gr */
+ {0x00FE, 0x8613}, /* White balance offset: B */
+ {0x0000, 0x8614}, /* White balance offset: Gb */
+
+ {0x0064, 0x8651}, /* R gain for white balance (L) */
+ {0x0040, 0x8652}, /* Gr gain for white balance (L) */
+ {0x0066, 0x8653}, /* B gain for white balance (L) */
+ {0x0040, 0x8654}, /* Gb gain for white balance (L) */
+ {0x0001, 0x863F}, /* Enable fixed gamma correction */
+
+ {0x00A1, 0x8656}, /* Size - Window1: 256x256, Window2: 128x128 */
+ /* UV division: UV no change, Enable New edge enhancement */
+ {0x0018, 0x8657}, /* Edge gain high threshold */
+ {0x0020, 0x8658}, /* Edge gain low threshold */
+ {0x000A, 0x8659}, /* Edge bandwidth high threshold */
+ {0x0005, 0x865A}, /* Edge bandwidth low threshold */
+ {0x0064, 0x8607}, /* UV filter enable */
+
+ {0x0016, 0x8660},
+ {0x0000, 0x86B0}, /* Bad pixels compensation address */
+ {0x00DC, 0x86B1}, /* X coord for bad pixels compensation (L) */
+ {0x0000, 0x86B2},
+ {0x0009, 0x86B3}, /* Y coord for bad pixels compensation (L) */
+ {0x0000, 0x86B4},
+
+ {0x0001, 0x86B0},
+ {0x00F5, 0x86B1},
+ {0x0000, 0x86B2},
+ {0x00C6, 0x86B3},
+ {0x0000, 0x86B4},
+
+ {0x0002, 0x86B0},
+ {0x001C, 0x86B1},
+ {0x0001, 0x86B2},
+ {0x00D7, 0x86B3},
+ {0x0000, 0x86B4},
+
+ {0x0003, 0x86B0},
+ {0x001C, 0x86B1},
+ {0x0001, 0x86B2},
+ {0x00D8, 0x86B3},
+ {0x0000, 0x86B4},
+
+ {0x0004, 0x86B0},
+ {0x001D, 0x86B1},
+ {0x0001, 0x86B2},
+ {0x00D8, 0x86B3},
+ {0x0000, 0x86B4},
+ {0x001E, 0x8660},
+
+ /* READ { 0, 0x0000, 0x8608 } ->
+ 0000: 13 */
+ /* READ { 0, 0x0000, 0x8609 } ->
+ 0000: 28 */
+ /* READ { 0, 0x0000, 0x8610 } ->
+ 0000: 05 */
+ /* READ { 0, 0x0000, 0x8611 } ->
+ 0000: 25 */
+ /* READ { 0, 0x0000, 0x8612 } ->
+ 0000: e1 */
+ /* READ { 0, 0x0000, 0x8613 } ->
+ 0000: fa */
+ /* READ { 0, 0x0000, 0x8614 } ->
+ 0000: f4 */
+ /* READ { 0, 0x0000, 0x8615 } ->
+ 0000: e8 */
+ /* READ { 0, 0x0000, 0x8616 } ->
+ 0000: 25 */
+ {}
+};
+
+static int reg_write(struct usb_device *dev,
+ __u16 index, __u16 value)
+{
+ int ret;
+
+ ret = usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0, /* request */
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x",
+ index, value);
+ if (ret < 0)
+ PDEBUG(D_ERR|D_USBO, "reg write: error %d", ret);
+ return ret;
+}
+
+/* read 1 byte */
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct gspca_dev *gspca_dev,
+ __u16 index) /* wIndex */
+{
+ int ret;
+
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0, /* register */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index,
+ gspca_dev->usb_buf, 1,
+ 500); /* timeout */
+ PDEBUG(D_USBI, "reg read i:%04x --> %02x",
+ index, gspca_dev->usb_buf[0]);
+ if (ret < 0) {
+ PDEBUG(D_ERR|D_USBI, "reg_read err %d", ret);
+ return ret;
+ }
+ return gspca_dev->usb_buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][3])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, i = 0;
+
+ while (data[i][1] != 0) {
+ ret = reg_write(dev, data[i][1], data[i][0]);
+ if (ret < 0)
+ return ret;
+ i++;
+ }
+ return 0;
+}
+
+/* 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;
+ __u16 product;
+ int data1, data2;
+
+ product = id->idProduct;
+ switch (id->idVendor) {
+ case 0x0130: /* Clone webcam */
+/* switch (product) { */
+/* case 0x0130: */
+ sd->subtype = HamaUSBSightcam; /* same as Hama 0010 */
+/* break; */
+/* } */
+ break;
+ case 0x041e: /* Creative cameras */
+/* switch (product) { */
+/* case 0x4018: */
+ sd->subtype = CreativeVista;
+/* break; */
+/* } */
+ break;
+ case 0x0461: /* MicroInnovation */
+/* switch (product) { */
+/* case 0x0815: */
+ sd->subtype = MicroInnovationIC200;
+/* break; */
+/* } */
+ break;
+ case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+/* switch (product) { */
+/* case 0x110: */
+ sd->subtype = ViewQuestVQ110;
+/* break; */
+/* } */
+ break;
+ case 0x0af9: /* Hama cameras */
+ switch (product) {
+ case 0x0010:
+ sd->subtype = HamaUSBSightcam;
+ break;
+ case 0x0011:
+ sd->subtype = HamaUSBSightcam2;
+ break;
+ }
+ break;
+ case 0x8086: /* Intel */
+/* switch (product) { */
+/* case 0x0110: */
+ sd->subtype = IntelEasyPCCamera;
+/* break; */
+/* } */
+ break;
+ }
+
+ /* Read from global register the USB product and vendor IDs, just to
+ * prove that we can communicate with the device. This works, which
+ * confirms at we are communicating properly and that the device
+ * is a 508. */
+ data1 = reg_read(gspca_dev, 0x8104);
+ data2 = reg_read(gspca_dev, 0x8105);
+ PDEBUG(D_PROBE, "Webcam Vendor ID: 0x%02x%02x", data2, data1);
+
+ data1 = reg_read(gspca_dev, 0x8106);
+ data2 = reg_read(gspca_dev, 0x8107);
+ PDEBUG(D_PROBE, "Webcam Product ID: 0x%02x%02x", data2, data1);
+
+ data1 = reg_read(gspca_dev, 0x8621);
+ PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1);
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = sif_mode;
+ cam->nmodes = ARRAY_SIZE(sif_mode);
+ sd->brightness = BRIGHTNESS_DEF;
+
+ switch (sd->subtype) {
+ case ViewQuestVQ110:
+ if (write_vector(gspca_dev, spca508_init_data))
+ return -1;
+ break;
+ default:
+/* case MicroInnovationIC200: */
+/* case IntelEasyPCCamera: */
+ if (write_vector(gspca_dev, spca508cs110_init_data))
+ return -1;
+ break;
+ case HamaUSBSightcam:
+ if (write_vector(gspca_dev, spca508_sightcam_init_data))
+ return -1;
+ break;
+ case HamaUSBSightcam2:
+ if (write_vector(gspca_dev, spca508_sightcam2_init_data))
+ return -1;
+ break;
+ case CreativeVista:
+ if (write_vector(gspca_dev, spca508_vista_init_data))
+ return -1;
+ break;
+ }
+ return 0; /* success */
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+/* write_vector(gspca_dev, spca508_open_data); */
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ int mode;
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ reg_write(gspca_dev->dev, 0x8500, mode);
+ switch (mode) {
+ case 0:
+ case 1:
+ reg_write(gspca_dev->dev, 0x8700, 0x28); /* clock */
+ break;
+ default:
+/* case 2: */
+/* case 3: */
+ reg_write(gspca_dev->dev, 0x8700, 0x23); /* clock */
+ break;
+ }
+ reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ /* Video ISO disable, Video Drop Packet enable: */
+ reg_write(gspca_dev->dev, 0x8112, 0x20);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+/* convert YUVY per line to YUYV (YUV 4:2:2) */
+static void yuvy_decode(unsigned char *out,
+ unsigned char *in,
+ int width,
+ int height)
+{
+ unsigned char *Ui, *Vi, *yi, *yi1;
+ unsigned char *out1;
+ int i, j;
+
+ yi = in;
+ for (i = height / 2; --i >= 0; ) {
+ out1 = out + width * 2; /* next line */
+ Ui = yi + width;
+ Vi = Ui + width / 2;
+ yi1 = Vi + width / 2;
+ for (j = width / 2; --j >= 0; ) {
+ *out++ = 128 + *yi++;
+ *out++ = 128 + *Ui;
+ *out++ = 128 + *yi++;
+ *out++ = 128 + *Vi;
+
+ *out1++ = 128 + *yi1++;
+ *out1++ = 128 + *Ui++;
+ *out1++ = 128 + *yi1++;
+ *out1++ = 128 + *Vi++;
+ }
+ yi += width * 2;
+ out = out1;
+ }
+}
+
+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 (data[0]) {
+ case 0: /* start of frame */
+ if (gspca_dev->last_packet_type == FIRST_PACKET) {
+ yuvy_decode(sd->tmpbuf2, sd->tmpbuf,
+ gspca_dev->width,
+ gspca_dev->height);
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame,
+ sd->tmpbuf2,
+ gspca_dev->width
+ * gspca_dev->height
+ * 2);
+ }
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, 0);
+ data += SPCA508_OFFSET_DATA;
+ len -= SPCA508_OFFSET_DATA;
+ if (len > 0)
+ memcpy(sd->tmpbuf, data, len);
+ else
+ len = 0;
+ sd->buflen = len;
+ return;
+ case 0xff: /* drop */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ data += 1;
+ len -= 1;
+ memcpy(&sd->tmpbuf[sd->buflen], data, len);
+ sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 brightness = sd->brightness;
+
+ /* MX seem contrast */
+ reg_write(gspca_dev->dev, 0x8651, brightness);
+ reg_write(gspca_dev->dev, 0x8652, brightness);
+ reg_write(gspca_dev->dev, 0x8653, brightness);
+ reg_write(gspca_dev->dev, 0x8654, brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = reg_read(gspca_dev, 0x8651);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0130, 0x0130), DVNM("Clone Digital Webcam 11043")},
+ {USB_DEVICE(0x041e, 0x4018), DVNM("Creative Webcam Vista (PD1100)")},
+ {USB_DEVICE(0x0461, 0x0815), DVNM("Micro Innovation IC200")},
+ {USB_DEVICE(0x0733, 0x0110), DVNM("ViewQuest VQ110")},
+ {USB_DEVICE(0x0af9, 0x0010), DVNM("Hama USB Sightcam 100")},
+ {USB_DEVICE(0x0af9, 0x0011), DVNM("Hama USB Sightcam 100")},
+ {USB_DEVICE(0x8086, 0x0110), DVNM("Intel Easy PC Camera")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
new file mode 100644
index 00000000000..b659bd0f788
--- /dev/null
+++ b/drivers/media/video/gspca/spca561.c
@@ -0,0 +1,1052 @@
+/*
+ * Sunplus spca561 subdriver
+ *
+ * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca561"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned short contrast;
+ __u8 brightness;
+ __u8 autogain;
+
+ __u8 chip_revision;
+ signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ .default_value = 32,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0x3fff,
+ .step = 1,
+ .default_value = 0x2000,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_AUTOGAIN 2
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 3},
+ {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 4 / 8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 4 / 8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+/*
+ * Initialization data
+ * I'm not very sure how to split initialization from open data
+ * chunks. For now, we'll consider everything as initialization
+ */
+/* Frame packet header offsets for the spca561 */
+#define SPCA561_OFFSET_SNAP 1
+#define SPCA561_OFFSET_TYPE 2
+#define SPCA561_OFFSET_COMPRESS 3
+#define SPCA561_OFFSET_FRAMSEQ 4
+#define SPCA561_OFFSET_GPIO 5
+#define SPCA561_OFFSET_USBBUFF 6
+#define SPCA561_OFFSET_WIN2GRAVE 7
+#define SPCA561_OFFSET_WIN2RAVE 8
+#define SPCA561_OFFSET_WIN2BAVE 9
+#define SPCA561_OFFSET_WIN2GBAVE 10
+#define SPCA561_OFFSET_WIN1GRAVE 11
+#define SPCA561_OFFSET_WIN1RAVE 12
+#define SPCA561_OFFSET_WIN1BAVE 13
+#define SPCA561_OFFSET_WIN1GBAVE 14
+#define SPCA561_OFFSET_FREQ 15
+#define SPCA561_OFFSET_VSYNC 16
+#define SPCA561_OFFSET_DATA 1
+#define SPCA561_INDEX_I2C_BASE 0x8800
+#define SPCA561_SNAPBIT 0x20
+#define SPCA561_SNAPCTRL 0x40
+enum {
+ Rev072A = 0,
+ Rev012A,
+};
+
+static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value)
+{
+ int ret;
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0, /* request */
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg write: error %d", ret);
+}
+
+static void write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][2])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int i;
+
+ i = 0;
+ while (data[i][1] != 0) {
+ reg_w_val(dev, data[i][1], data[i][0]);
+ i++;
+ }
+}
+
+/* read 'len' bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+ __u16 index, __u16 length)
+{
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, length, 500);
+}
+
+static void reg_w_buf(struct gspca_dev *gspca_dev,
+ __u16 index, const __u8 *buffer, __u16 len)
+{
+ memcpy(gspca_dev->usb_buf, buffer, len);
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, len, 500);
+}
+
+static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode)
+{
+ reg_w_val(gspca_dev->dev, 0x92, 0x8804);
+ reg_w_val(gspca_dev->dev, mode, 0x8802);
+}
+
+static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
+{
+ int retry = 60;
+ __u8 DataLow;
+ __u8 DataHight;
+
+ DataLow = valeur;
+ DataHight = valeur >> 8;
+ reg_w_val(gspca_dev->dev, reg, 0x8801);
+ reg_w_val(gspca_dev->dev, DataLow, 0x8805);
+ reg_w_val(gspca_dev->dev, DataHight, 0x8800);
+ while (retry--) {
+ reg_r(gspca_dev, 0x8803, 1);
+ if (!gspca_dev->usb_buf[0])
+ break;
+ }
+}
+
+static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
+{
+ int retry = 60;
+ __u8 value;
+ __u8 vallsb;
+
+ reg_w_val(gspca_dev->dev, 0x92, 0x8804);
+ reg_w_val(gspca_dev->dev, reg, 0x8801);
+ reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802);
+ while (retry--) {
+ reg_r(gspca_dev, 0x8803, 1);
+ if (!gspca_dev->usb_buf)
+ break;
+ }
+ if (retry == 0)
+ return -1;
+ reg_r(gspca_dev, 0x8800, 1);
+ value = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8805, 1);
+ vallsb = gspca_dev->usb_buf[0];
+ return ((int) value << 8) | vallsb;
+}
+
+static const __u16 spca561_init_data[][2] = {
+ {0x0000, 0x8114}, /* Software GPIO output data */
+ {0x0001, 0x8114}, /* Software GPIO output data */
+ {0x0000, 0x8112}, /* Some kind of reset */
+ {0x0003, 0x8701}, /* PCLK clock delay adjustment */
+ {0x0001, 0x8703}, /* HSYNC from cmos inverted */
+ {0x0011, 0x8118}, /* Enable and conf sensor */
+ {0x0001, 0x8118}, /* Conf sensor */
+ {0x0092, 0x8804}, /* I know nothing about these */
+ {0x0010, 0x8802}, /* 0x88xx registers, so I won't */
+ /***************/
+ {0x000d, 0x8805}, /* sensor default setting */
+ {0x0001, 0x8801}, /* 1 <- 0x0d */
+ {0x0000, 0x8800},
+ {0x0018, 0x8805},
+ {0x0002, 0x8801}, /* 2 <- 0x18 */
+ {0x0000, 0x8800},
+ {0x0065, 0x8805},
+ {0x0004, 0x8801}, /* 4 <- 0x01 0x65 */
+ {0x0001, 0x8800},
+ {0x0021, 0x8805},
+ {0x0005, 0x8801}, /* 5 <- 0x21 */
+ {0x0000, 0x8800},
+ {0x00aa, 0x8805},
+ {0x0007, 0x8801}, /* 7 <- 0xaa */
+ {0x0000, 0x8800},
+ {0x0004, 0x8805},
+ {0x0020, 0x8801}, /* 0x20 <- 0x15 0x04 */
+ {0x0015, 0x8800},
+ {0x0002, 0x8805},
+ {0x0039, 0x8801}, /* 0x39 <- 0x02 */
+ {0x0000, 0x8800},
+ {0x0010, 0x8805},
+ {0x0035, 0x8801}, /* 0x35 <- 0x10 */
+ {0x0000, 0x8800},
+ {0x0049, 0x8805},
+ {0x0009, 0x8801}, /* 0x09 <- 0x10 0x49 */
+ {0x0010, 0x8800},
+ {0x000b, 0x8805},
+ {0x0028, 0x8801}, /* 0x28 <- 0x0b */
+ {0x0000, 0x8800},
+ {0x000f, 0x8805},
+ {0x003b, 0x8801}, /* 0x3b <- 0x0f */
+ {0x0000, 0x8800},
+ {0x0000, 0x8805},
+ {0x003c, 0x8801}, /* 0x3c <- 0x00 */
+ {0x0000, 0x8800},
+ /***************/
+ {0x0018, 0x8601}, /* Pixel/line selection for color separation */
+ {0x0000, 0x8602}, /* Optical black level for user setting */
+ {0x0060, 0x8604}, /* Optical black horizontal offset */
+ {0x0002, 0x8605}, /* Optical black vertical offset */
+ {0x0000, 0x8603}, /* Non-automatic optical black level */
+ {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
+ {0x0000, 0x865f}, /* Vertical valid pixels window (x2) */
+ {0x00b0, 0x865d}, /* Horizontal valid pixels window (x2) */
+ {0x0090, 0x865e}, /* Vertical valid lines window (x2) */
+ {0x00e0, 0x8406}, /* Memory buffer threshold */
+ {0x0000, 0x8660}, /* Compensation memory stuff */
+ {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */
+ {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
+ {0x0001, 0x8200}, /* OprMode to be executed by hardware */
+ {0x0007, 0x8201}, /* Output address for r/w serial EEPROM */
+ {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
+ {0x0001, 0x8200}, /* OprMode to be executed by hardware */
+ {0x0010, 0x8660}, /* Compensation memory stuff */
+ {0x0018, 0x8660}, /* Compensation memory stuff */
+
+ {0x0004, 0x8611}, /* R offset for white balance */
+ {0x0004, 0x8612}, /* Gr offset for white balance */
+ {0x0007, 0x8613}, /* B offset for white balance */
+ {0x0000, 0x8614}, /* Gb offset for white balance */
+ {0x008c, 0x8651}, /* R gain for white balance */
+ {0x008c, 0x8652}, /* Gr gain for white balance */
+ {0x00b5, 0x8653}, /* B gain for white balance */
+ {0x008c, 0x8654}, /* Gb gain for white balance */
+ {0x0002, 0x8502}, /* Maximum average bit rate stuff */
+
+ {0x0011, 0x8802},
+ {0x0087, 0x8700}, /* Set master clock (96Mhz????) */
+ {0x0081, 0x8702}, /* Master clock output enable */
+
+ {0x0000, 0x8500}, /* Set image type (352x288 no compression) */
+ /* Originally was 0x0010 (352x288 compression) */
+
+ {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
+ {0x0003, 0x865c}, /* Vertical offset for valid lines */
+ /***************//* sensor active */
+ {0x0003, 0x8801}, /* 0x03 <- 0x01 0x21 //289 */
+ {0x0021, 0x8805},
+ {0x0001, 0x8800},
+ {0x0004, 0x8801}, /* 0x04 <- 0x01 0x65 //357 */
+ {0x0065, 0x8805},
+ {0x0001, 0x8800},
+ {0x0005, 0x8801}, /* 0x05 <- 0x2f */
+ {0x002f, 0x8805},
+ {0x0000, 0x8800},
+ {0x0006, 0x8801}, /* 0x06 <- 0 */
+ {0x0000, 0x8805},
+ {0x0000, 0x8800},
+ {0x000a, 0x8801}, /* 0x0a <- 2 */
+ {0x0002, 0x8805},
+ {0x0000, 0x8800},
+ {0x0009, 0x8801}, /* 0x09 <- 0x1061 */
+ {0x0061, 0x8805},
+ {0x0010, 0x8800},
+ {0x0035, 0x8801}, /* 0x35 <-0x14 */
+ {0x0014, 0x8805},
+ {0x0000, 0x8800},
+ {0x0030, 0x8112}, /* ISO and drop packet enable */
+ {0x0000, 0x8112}, /* Some kind of reset ???? */
+ {0x0009, 0x8118}, /* Enable sensor and set standby */
+ {0x0000, 0x8114}, /* Software GPIO output data */
+ {0x0000, 0x8114}, /* Software GPIO output data */
+ {0x0001, 0x8114}, /* Software GPIO output data */
+ {0x0000, 0x8112}, /* Some kind of reset ??? */
+ {0x0003, 0x8701},
+ {0x0001, 0x8703},
+ {0x0011, 0x8118},
+ {0x0001, 0x8118},
+ /***************/
+ {0x0092, 0x8804},
+ {0x0010, 0x8802},
+ {0x000d, 0x8805},
+ {0x0001, 0x8801},
+ {0x0000, 0x8800},
+ {0x0018, 0x8805},
+ {0x0002, 0x8801},
+ {0x0000, 0x8800},
+ {0x0065, 0x8805},
+ {0x0004, 0x8801},
+ {0x0001, 0x8800},
+ {0x0021, 0x8805},
+ {0x0005, 0x8801},
+ {0x0000, 0x8800},
+ {0x00aa, 0x8805},
+ {0x0007, 0x8801}, /* mode 0xaa */
+ {0x0000, 0x8800},
+ {0x0004, 0x8805},
+ {0x0020, 0x8801},
+ {0x0015, 0x8800}, /* mode 0x0415 */
+ {0x0002, 0x8805},
+ {0x0039, 0x8801},
+ {0x0000, 0x8800},
+ {0x0010, 0x8805},
+ {0x0035, 0x8801},
+ {0x0000, 0x8800},
+ {0x0049, 0x8805},
+ {0x0009, 0x8801},
+ {0x0010, 0x8800},
+ {0x000b, 0x8805},
+ {0x0028, 0x8801},
+ {0x0000, 0x8800},
+ {0x000f, 0x8805},
+ {0x003b, 0x8801},
+ {0x0000, 0x8800},
+ {0x0000, 0x8805},
+ {0x003c, 0x8801},
+ {0x0000, 0x8800},
+ {0x0002, 0x8502},
+ {0x0039, 0x8801},
+ {0x0000, 0x8805},
+ {0x0000, 0x8800},
+
+ {0x0087, 0x8700}, /* overwrite by start */
+ {0x0081, 0x8702},
+ {0x0000, 0x8500},
+/* {0x0010, 0x8500}, -- Previous line was this */
+ {0x0002, 0x865b},
+ {0x0003, 0x865c},
+ /***************/
+ {0x0003, 0x8801}, /* 0x121-> 289 */
+ {0x0021, 0x8805},
+ {0x0001, 0x8800},
+ {0x0004, 0x8801}, /* 0x165 -> 357 */
+ {0x0065, 0x8805},
+ {0x0001, 0x8800},
+ {0x0005, 0x8801}, /* 0x2f //blanking control colonne */
+ {0x002f, 0x8805},
+ {0x0000, 0x8800},
+ {0x0006, 0x8801}, /* 0x00 //blanking mode row */
+ {0x0000, 0x8805},
+ {0x0000, 0x8800},
+ {0x000a, 0x8801}, /* 0x01 //0x02 */
+ {0x0001, 0x8805},
+ {0x0000, 0x8800},
+ {0x0009, 0x8801}, /* 0x1061 - setexposure times && pixel clock
+ * 0001 0 | 000 0110 0001 */
+ {0x0061, 0x8805}, /* 61 31 */
+ {0x0008, 0x8800}, /* 08 */
+ {0x0035, 0x8801}, /* 0x14 - set gain general */
+ {0x001f, 0x8805}, /* 0x14 */
+ {0x0000, 0x8800},
+ {0x0030, 0x8112},
+ {}
+};
+
+static void sensor_reset(struct gspca_dev *gspca_dev)
+{
+ reg_w_val(gspca_dev->dev, 0x8631, 0xc8);
+ reg_w_val(gspca_dev->dev, 0x8634, 0xc8);
+ reg_w_val(gspca_dev->dev, 0x8112, 0x00);
+ reg_w_val(gspca_dev->dev, 0x8114, 0x00);
+ reg_w_val(gspca_dev->dev, 0x8118, 0x21);
+ i2c_init(gspca_dev, 0x14);
+ i2c_write(gspca_dev, 1, 0x0d);
+ i2c_write(gspca_dev, 0, 0x0d);
+}
+
+/******************** QC Express etch2 stuff ********************/
+static const __u16 Pb100_1map8300[][2] = {
+ /* reg, value */
+ {0x8320, 0x3304},
+
+ {0x8303, 0x0125}, /* image area */
+ {0x8304, 0x0169},
+ {0x8328, 0x000b},
+ {0x833c, 0x0001},
+
+ {0x832f, 0x0419},
+ {0x8307, 0x00aa},
+ {0x8301, 0x0003},
+ {0x8302, 0x000e},
+ {}
+};
+static const __u16 Pb100_2map8300[][2] = {
+ /* reg, value */
+ {0x8339, 0x0000},
+ {0x8307, 0x00aa},
+ {}
+};
+
+static const __u16 spca561_161rev12A_data1[][2] = {
+ {0x21, 0x8118},
+ {0x01, 0x8114},
+ {0x00, 0x8112},
+ {0x92, 0x8804},
+ {0x04, 0x8802}, /* windows uses 08 */
+ {}
+};
+static const __u16 spca561_161rev12A_data2[][2] = {
+ {0x21, 0x8118},
+ {0x10, 0x8500},
+ {0x07, 0x8601},
+ {0x07, 0x8602},
+ {0x04, 0x8501},
+ {0x21, 0x8118},
+
+ {0x07, 0x8201}, /* windows uses 02 */
+ {0x08, 0x8200},
+ {0x01, 0x8200},
+
+ {0x00, 0x8114},
+ {0x01, 0x8114}, /* windows uses 00 */
+
+ {0x90, 0x8604},
+ {0x00, 0x8605},
+ {0xb0, 0x8603},
+
+ /* sensor gains */
+ {0x00, 0x8610}, /* *red */
+ {0x00, 0x8611}, /* 3f *green */
+ {0x00, 0x8612}, /* green *blue */
+ {0x00, 0x8613}, /* blue *green */
+ {0x35, 0x8614}, /* green *red */
+ {0x35, 0x8615}, /* 40 *green */
+ {0x35, 0x8616}, /* 7a *blue */
+ {0x35, 0x8617}, /* 40 *green */
+
+ {0x0c, 0x8620}, /* 0c */
+ {0xc8, 0x8631}, /* c8 */
+ {0xc8, 0x8634}, /* c8 */
+ {0x23, 0x8635}, /* 23 */
+ {0x1f, 0x8636}, /* 1f */
+ {0xdd, 0x8637}, /* dd */
+ {0xe1, 0x8638}, /* e1 */
+ {0x1d, 0x8639}, /* 1d */
+ {0x21, 0x863a}, /* 21 */
+ {0xe3, 0x863b}, /* e3 */
+ {0xdf, 0x863c}, /* df */
+ {0xf0, 0x8505},
+ {0x32, 0x850a},
+ {}
+};
+
+static void sensor_mapwrite(struct gspca_dev *gspca_dev,
+ const __u16 sensormap[][2])
+{
+ int i = 0;
+ __u8 usbval[2];
+
+ while (sensormap[i][0]) {
+ usbval[0] = sensormap[i][1];
+ usbval[1] = sensormap[i][1] >> 8;
+ reg_w_buf(gspca_dev, sensormap[i][0], usbval, 2);
+ i++;
+ }
+}
+static void init_161rev12A(struct gspca_dev *gspca_dev)
+{
+ sensor_reset(gspca_dev);
+ write_vector(gspca_dev, spca561_161rev12A_data1);
+ sensor_mapwrite(gspca_dev, Pb100_1map8300);
+ write_vector(gspca_dev, spca561_161rev12A_data2);
+ sensor_mapwrite(gspca_dev, Pb100_2map8300);
+}
+
+/* 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;
+ __u16 vendor, product;
+ __u8 data1, data2;
+
+ /* Read frm global register the USB product and vendor IDs, just to
+ * prove that we can communicate with the device. This works, which
+ * confirms at we are communicating properly and that the device
+ * is a 561. */
+ reg_r(gspca_dev, 0x8104, 1);
+ data1 = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8105, 1);
+ data2 = gspca_dev->usb_buf[0];
+ vendor = (data2 << 8) | data1;
+ reg_r(gspca_dev, 0x8106, 1);
+ data1 = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8107, 1);
+ data2 = gspca_dev->usb_buf[0];
+ product = (data2 << 8) | data1;
+ if (vendor != id->idVendor || product != id->idProduct) {
+ PDEBUG(D_PROBE, "Bad vendor / product from device");
+ return -EINVAL;
+ }
+ switch (product) {
+ case 0x0928:
+ case 0x0929:
+ case 0x092a:
+ case 0x092b:
+ case 0x092c:
+ case 0x092d:
+ case 0x092e:
+ case 0x092f:
+ case 0x403b:
+ sd->chip_revision = Rev012A;
+ break;
+ default:
+/* case 0x0561:
+ case 0x0815: * ?? in spca508.c
+ case 0x401a:
+ case 0x7004:
+ case 0x7e50:
+ case 0xa001:
+ case 0xcdee: */
+ sd->chip_revision = Rev072A;
+ break;
+ }
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
+ cam->cam_mode = sif_mode;
+ cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->chip_revision) {
+ case Rev072A:
+ PDEBUG(D_STREAM, "Chip revision id: 072a");
+ write_vector(gspca_dev, spca561_init_data);
+ break;
+ default:
+/* case Rev012A: */
+ PDEBUG(D_STREAM, "Chip revision id: 012a");
+ init_161rev12A(gspca_dev);
+ break;
+ }
+ return 0;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 lowb;
+ int expotimes;
+
+ switch (sd->chip_revision) {
+ case Rev072A:
+ lowb = sd->contrast >> 8;
+ reg_w_val(dev, lowb, 0x8651);
+ reg_w_val(dev, lowb, 0x8652);
+ reg_w_val(dev, lowb, 0x8653);
+ reg_w_val(dev, lowb, 0x8654);
+ break;
+ case Rev012A: {
+ __u8 Reg8391[] =
+ { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 };
+
+ /* Write camera sensor settings */
+ expotimes = (sd->contrast >> 5) & 0x07ff;
+ Reg8391[0] = expotimes & 0xff; /* exposure */
+ Reg8391[1] = 0x18 | (expotimes >> 8);
+ Reg8391[2] = sd->brightness; /* gain */
+ reg_w_buf(gspca_dev, 0x8391, Reg8391, 8);
+ reg_w_buf(gspca_dev, 0x8390, Reg8391, 8);
+ break;
+ }
+ }
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int Clck;
+ __u8 Reg8307[] = { 0xaa, 0x00 };
+ int mode;
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ switch (sd->chip_revision) {
+ case Rev072A:
+ switch (mode) {
+ default:
+/* case 0:
+ case 1: */
+ Clck = 0x25;
+ break;
+ case 2:
+ Clck = 0x22;
+ break;
+ case 3:
+ Clck = 0x21;
+ break;
+ }
+ reg_w_val(dev, 0x8500, mode); /* mode */
+ reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
+ reg_w_val(dev, 0x8112, 0x10 | 0x20);
+ break;
+ default:
+/* case Rev012A: */
+ switch (mode) {
+ case 0:
+ case 1:
+ Clck = 0x8a;
+ break;
+ case 2:
+ Clck = 0x85;
+ break;
+ default:
+ Clck = 0x83;
+ break;
+ }
+ if (mode <= 1) {
+ /* Use compression on 320x240 and above */
+ reg_w_val(dev, 0x8500, 0x10 | mode);
+ } else {
+ /* I couldn't get the compression to work below 320x240
+ * Fortunately at these resolutions the bandwidth
+ * is sufficient to push raw frames at ~20fps */
+ reg_w_val(dev, 0x8500, mode);
+ } /* -- qq@kuku.eu.org */
+ reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
+ reg_w_val(gspca_dev->dev, 0x8700, Clck);
+ /* 0x8f 0x85 0x27 clock */
+ reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
+ reg_w_val(gspca_dev->dev, 0x850b, 0x03);
+ setcontrast(gspca_dev);
+ break;
+ }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+ reg_w_val(gspca_dev->dev, 0x8114, 0);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int expotimes = 0;
+ int pixelclk = 0;
+ int gainG = 0;
+ __u8 R, Gr, Gb, B;
+ int y;
+ __u8 luma_mean = 110;
+ __u8 luma_delta = 20;
+ __u8 spring = 4;
+
+ switch (sd->chip_revision) {
+ case Rev072A:
+ reg_r(gspca_dev, 0x8621, 1);
+ Gr = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8622, 1);
+ R = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8623, 1);
+ B = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8624, 1);
+ Gb = gspca_dev->usb_buf[0];
+ y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8;
+ /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */
+ /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */
+ /* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */
+
+ if (y < luma_mean - luma_delta ||
+ y > luma_mean + luma_delta) {
+ expotimes = i2c_read(gspca_dev, 0x09, 0x10);
+ pixelclk = 0x0800;
+ expotimes = expotimes & 0x07ff;
+ /* PDEBUG(D_PACK,
+ "Exposition Times 0x%03X Clock 0x%04X ",
+ expotimes,pixelclk); */
+ gainG = i2c_read(gspca_dev, 0x35, 0x10);
+ /* PDEBUG(D_PACK,
+ "reading Gain register %d", gainG); */
+
+ expotimes += (luma_mean - y) >> spring;
+ gainG += (luma_mean - y) / 50;
+ /* PDEBUG(D_PACK,
+ "compute expotimes %d gain %d",
+ expotimes,gainG); */
+
+ if (gainG > 0x3f)
+ gainG = 0x3f;
+ else if (gainG < 4)
+ gainG = 3;
+ i2c_write(gspca_dev, gainG, 0x35);
+
+ if (expotimes >= 0x0256)
+ expotimes = 0x0256;
+ else if (expotimes < 4)
+ expotimes = 3;
+ i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
+ }
+ break;
+ case Rev012A:
+ /* sensor registers is access and memory mapped to 0x8300 */
+ /* readind all 0x83xx block the sensor */
+ /*
+ * The data from the header seem wrong where is the luma
+ * and chroma mean value
+ * at the moment set exposure in contrast set
+ */
+ break;
+ }
+}
+
+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 (data[0]) {
+ case 0: /* start of frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+ if (sd->ag_cnt >= 0) {
+ if (--sd->ag_cnt < 0) {
+ sd->ag_cnt = AG_CNT_START;
+ setautogain(gspca_dev);
+ }
+ }
+ data += SPCA561_OFFSET_DATA;
+ len -= SPCA561_OFFSET_DATA;
+ if (data[1] & 0x10) {
+ /* compressed bayer */
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ frame, data, len);
+ } else {
+ /* raw bayer (with a header, which we skip) */
+ data += 20;
+ len -= 20;
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ frame, data, len);
+ }
+ return;
+ case 0xff: /* drop */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ data++;
+ len--;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 value;
+
+ switch (sd->chip_revision) {
+ case Rev072A:
+ value = sd->brightness;
+ reg_w_val(gspca_dev->dev, value, 0x8611);
+ reg_w_val(gspca_dev->dev, value, 0x8612);
+ reg_w_val(gspca_dev->dev, value, 0x8613);
+ reg_w_val(gspca_dev->dev, value, 0x8614);
+ break;
+ default:
+/* case Rev012A: */
+ setcontrast(gspca_dev);
+ break;
+ }
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u16 tot;
+
+ switch (sd->chip_revision) {
+ case Rev072A:
+ tot = 0;
+ reg_r(gspca_dev, 0x8611, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8612, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8613, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8614, 1);
+ tot += gspca_dev->usb_buf[0];
+ sd->brightness = tot >> 2;
+ break;
+ default:
+/* case Rev012A: */
+ /* no way to read sensor settings */
+ break;
+ }
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u16 tot;
+
+ switch (sd->chip_revision) {
+ case Rev072A:
+ tot = 0;
+ reg_r(gspca_dev, 0x8651, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8652, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8653, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8654, 1);
+ tot += gspca_dev->usb_buf[0];
+ sd->contrast = tot << 6;
+ break;
+ default:
+/* case Rev012A: */
+ /* no way to read sensor settings */
+ break;
+ }
+ PDEBUG(D_CONF, "get contrast %d", sd->contrast);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (val)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x401a), DVNM("Creative Webcam Vista (PD1100)")},
+ {USB_DEVICE(0x041e, 0x403b), DVNM("Creative Webcam Vista (VF0010)")},
+ {USB_DEVICE(0x0458, 0x7004), DVNM("Genius VideoCAM Express V2")},
+ {USB_DEVICE(0x046d, 0x0928), DVNM("Logitech QC Express Etch2")},
+ {USB_DEVICE(0x046d, 0x0929), DVNM("Labtec Webcam Elch2")},
+ {USB_DEVICE(0x046d, 0x092a), DVNM("Logitech QC for Notebook")},
+ {USB_DEVICE(0x046d, 0x092b), DVNM("Labtec Webcam Plus")},
+ {USB_DEVICE(0x046d, 0x092c), DVNM("Logitech QC chat Elch2")},
+ {USB_DEVICE(0x046d, 0x092d), DVNM("Logitech QC Elch2")},
+ {USB_DEVICE(0x046d, 0x092e), DVNM("Logitech QC Elch2")},
+ {USB_DEVICE(0x046d, 0x092f), DVNM("Logitech QC Elch2")},
+ {USB_DEVICE(0x04fc, 0x0561), DVNM("Flexcam 100")},
+ {USB_DEVICE(0x060b, 0xa001), DVNM("Maxell Compact Pc PM3")},
+ {USB_DEVICE(0x10fd, 0x7e50), DVNM("FlyCam Usb 100")},
+ {USB_DEVICE(0xabcd, 0xcdee), DVNM("Petcam")},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
new file mode 100644
index 00000000000..c78ee0d3e59
--- /dev/null
+++ b/drivers/media/video/gspca/stk014.c
@@ -0,0 +1,592 @@
+/*
+ * Syntek DV4000 (STK014) subdriver
+ *
+ * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "stk014"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char lightfreq;
+};
+
+/* global parameters */
+static int sd_quant = 7; /* <= 4 KO - 7: good (enough!) */
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 127
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define CONTRAST_DEF 127
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define COLOR_DEF 127
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light frequency filter",
+ .minimum = 1,
+ .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
+ .step = 1,
+#define FREQ_DEF 1
+ .default_value = FREQ_DEF,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/* -- read a register -- */
+static int reg_r(struct gspca_dev *gspca_dev,
+ __u16 index)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0x00,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x00,
+ index,
+ gspca_dev->usb_buf, 1,
+ 500);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_r err %d", ret);
+ return ret;
+ }
+ return gspca_dev->usb_buf[0];
+}
+
+/* -- write a register -- */
+static int reg_w(struct gspca_dev *gspca_dev,
+ __u16 index, __u16 value)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x01,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value,
+ index,
+ NULL,
+ 0,
+ 500);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg_w err %d", ret);
+ return ret;
+}
+
+/* -- get a bulk value (4 bytes) -- */
+static int rcv_val(struct gspca_dev *gspca_dev,
+ int ads)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int alen, ret;
+
+ reg_w(gspca_dev, 0x634, (ads >> 16) & 0xff);
+ reg_w(gspca_dev, 0x635, (ads >> 8) & 0xff);
+ reg_w(gspca_dev, 0x636, ads & 0xff);
+ reg_w(gspca_dev, 0x637, 0);
+ reg_w(gspca_dev, 0x638, 4); /* len & 0xff */
+ reg_w(gspca_dev, 0x639, 0); /* len >> 8 */
+ reg_w(gspca_dev, 0x63a, 0);
+ reg_w(gspca_dev, 0x63b, 0);
+ reg_w(gspca_dev, 0x630, 5);
+ ret = usb_bulk_msg(dev,
+ usb_rcvbulkpipe(dev, 5),
+ gspca_dev->usb_buf,
+ 4, /* length */
+ &alen,
+ 500); /* timeout in milliseconds */
+ return ret;
+}
+
+/* -- send a bulk value -- */
+static int snd_val(struct gspca_dev *gspca_dev,
+ int ads,
+ unsigned int val)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int alen, ret;
+ __u8 seq = 0;
+
+ if (ads == 0x003f08) {
+ ret = reg_r(gspca_dev, 0x0704);
+ if (ret < 0)
+ goto ko;
+ ret = reg_r(gspca_dev, 0x0705);
+ if (ret < 0)
+ goto ko;
+ seq = ret; /* keep the sequence number */
+ ret = reg_r(gspca_dev, 0x0650);
+ if (ret < 0)
+ goto ko;
+ reg_w(gspca_dev, 0x654, seq);
+ } else {
+ reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff);
+ }
+ reg_w(gspca_dev, 0x655, (ads >> 8) & 0xff);
+ reg_w(gspca_dev, 0x656, ads & 0xff);
+ reg_w(gspca_dev, 0x657, 0);
+ reg_w(gspca_dev, 0x658, 0x04); /* size */
+ reg_w(gspca_dev, 0x659, 0);
+ reg_w(gspca_dev, 0x65a, 0);
+ reg_w(gspca_dev, 0x65b, 0);
+ reg_w(gspca_dev, 0x650, 5);
+ gspca_dev->usb_buf[0] = val >> 24;
+ gspca_dev->usb_buf[1] = val >> 16;
+ gspca_dev->usb_buf[2] = val >> 8;
+ gspca_dev->usb_buf[3] = val;
+ ret = usb_bulk_msg(dev,
+ usb_sndbulkpipe(dev, 6),
+ gspca_dev->usb_buf,
+ 4,
+ &alen,
+ 500); /* timeout in milliseconds */
+ if (ret < 0)
+ goto ko;
+ if (ads == 0x003f08) {
+ seq += 4;
+ seq &= 0x3f;
+ reg_w(gspca_dev, 0x705, seq);
+ }
+ return ret;
+ko:
+ PDEBUG(D_ERR, "snd_val err %d", ret);
+ return ret;
+}
+
+/* set a camera parameter */
+static int set_par(struct gspca_dev *gspca_dev,
+ int parval)
+{
+ return snd_val(gspca_dev, 0x003f08, parval);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int parval;
+
+ parval = 0x06000000 /* whiteness */
+ + (sd->brightness << 16);
+ set_par(gspca_dev, parval);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int parval;
+
+ parval = 0x07000000 /* contrast */
+ + (sd->contrast << 16);
+ set_par(gspca_dev, parval);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int parval;
+
+ parval = 0x08000000 /* saturation */
+ + (sd->colors << 16);
+ set_par(gspca_dev, parval);
+}
+
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ set_par(gspca_dev, sd->lightfreq == 1
+ ? 0x33640000 /* 50 Hz */
+ : 0x33780000); /* 60 Hz */
+}
+
+/* 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 = &gspca_dev->cam;
+
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x02;
+ gspca_dev->cam.cam_mode = vga_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ sd->lightfreq = FREQ_DEF;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ int ret;
+
+ /* check if the device responds */
+ usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+ ret = reg_r(gspca_dev, 0x0740);
+ if (ret < 0)
+ return ret;
+ if (ret != 0xff) {
+ PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret);
+ return -1;
+ }
+ return 0;
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ int ret, value;
+
+ /* work on alternate 1 */
+ usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+
+ set_par(gspca_dev, 0x10000000);
+ set_par(gspca_dev, 0x00000000);
+ set_par(gspca_dev, 0x8002e001);
+ set_par(gspca_dev, 0x14000000);
+ if (gspca_dev->width > 320)
+ value = 0x8002e001; /* 640x480 */
+ else
+ value = 0x4001f000; /* 320x240 */
+ set_par(gspca_dev, value);
+ ret = usb_set_interface(gspca_dev->dev,
+ gspca_dev->iface,
+ gspca_dev->alt);
+ if (ret < 0) {
+ PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed",
+ gspca_dev->iface, gspca_dev->alt);
+ goto out;
+ }
+ ret = reg_r(gspca_dev, 0x0630);
+ if (ret < 0)
+ goto out;
+ rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */
+ ret = reg_r(gspca_dev, 0x0650);
+ if (ret < 0)
+ goto out;
+ snd_val(gspca_dev, 0x000020, 0xffffffff);
+ reg_w(gspca_dev, 0x0620, 0);
+ reg_w(gspca_dev, 0x0630, 0);
+ reg_w(gspca_dev, 0x0640, 0);
+ reg_w(gspca_dev, 0x0650, 0);
+ reg_w(gspca_dev, 0x0660, 0);
+ setbrightness(gspca_dev); /* whiteness */
+ setcontrast(gspca_dev); /* contrast */
+ setcolors(gspca_dev); /* saturation */
+ set_par(gspca_dev, 0x09800000); /* Red ? */
+ set_par(gspca_dev, 0x0a800000); /* Green ? */
+ set_par(gspca_dev, 0x0b800000); /* Blue ? */
+ set_par(gspca_dev, 0x0d030000); /* Gamma ? */
+ setfreq(gspca_dev); /* light frequency */
+
+ /* start the video flow */
+ set_par(gspca_dev, 0x01000000);
+ set_par(gspca_dev, 0x01000000);
+ PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
+ return;
+out:
+ PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ set_par(gspca_dev, 0x02000000);
+ set_par(gspca_dev, 0x02000000);
+ usb_set_interface(dev, gspca_dev->iface, 1);
+ reg_r(gspca_dev, 0x0630);
+ rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */
+ reg_r(gspca_dev, 0x0650);
+ snd_val(gspca_dev, 0x000020, 0xffffffff);
+ reg_w(gspca_dev, 0x0620, 0);
+ reg_w(gspca_dev, 0x0630, 0);
+ reg_w(gspca_dev, 0x0640, 0);
+ reg_w(gspca_dev, 0x0650, 0);
+ reg_w(gspca_dev, 0x0660, 0);
+ PDEBUG(D_STREAM, "camera stopped");
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ static unsigned char ffd9[] = {0xff, 0xd9};
+
+ /* a frame starts with:
+ * - 0xff 0xfe
+ * - 0x08 0x00 - length (little endian ?!)
+ * - 4 bytes = size of whole frame (BE - including header)
+ * - 0x00 0x0c
+ * - 0xff 0xd8
+ * - .. JPEG image with escape sequences (ff 00)
+ * (without ending - ff d9)
+ */
+ if (data[0] == 0xff && data[1] == 0xfe) {
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ ffd9, 2);
+
+ /* put the JPEG 411 header */
+ jpeg_put_header(gspca_dev, frame, sd_quant, 0x22);
+
+ /* beginning of the frame */
+#define STKHDRSZ 12
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data + STKHDRSZ, len - STKHDRSZ);
+#undef STKHDRSZ
+ return;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->lightfreq = val;
+ if (gspca_dev->streaming)
+ setfreq(gspca_dev);
+ return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->lightfreq;
+ return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x05e1, 0x0893), DVNM("Syntek DV4000")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ info("v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param_named(quant, sd_quant, int, 0644);
+MODULE_PARM_DESC(quant, "Quantization index (0..8)");
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
new file mode 100644
index 00000000000..abd7bef9b3d
--- /dev/null
+++ b/drivers/media/video/gspca/sunplus.c
@@ -0,0 +1,1677 @@
+/*
+ * Sunplus spca504(abc) spca533 spca536 library
+ * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sunplus"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 8)
+static const char version[] = "2.1.8";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ __u8 packet[ISO_MAX_SIZE + 128];
+ /* !! no more than 128 ff in an ISO packet */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char autogain;
+
+ char qindex;
+ char bridge;
+#define BRIDGE_SPCA504 0
+#define BRIDGE_SPCA504B 1
+#define BRIDGE_SPCA504C 2
+#define BRIDGE_SPCA533 3
+#define BRIDGE_SPCA536 4
+ char subtype;
+#define AiptekMiniPenCam13 1
+#define LogitechClickSmart420 2
+#define LogitechClickSmart820 3
+#define MegapixV4 4
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x20,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_COLOR 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x1a,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+#define SD_AUTOGAIN 3
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+};
+
+static struct v4l2_pix_format custom_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 464,
+ .sizeimage = 464 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+};
+
+static struct v4l2_pix_format vga_mode2[] = {
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 4},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
+#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
+#define SPCA504_PCCAM600_OFFSET_MODE 5
+#define SPCA504_PCCAM600_OFFSET_DATA 14
+ /* Frame packet header offsets for the spca533 */
+#define SPCA533_OFFSET_DATA 16
+#define SPCA533_OFFSET_FRAMSEQ 15
+/* Frame packet header offsets for the spca536 */
+#define SPCA536_OFFSET_DATA 4
+#define SPCA536_OFFSET_FRAMSEQ 1
+
+/* Initialisation data for the Creative PC-CAM 600 */
+static const __u16 spca504_pccam600_init_data[][3] = {
+/* {0xa0, 0x0000, 0x0503}, * capture mode */
+ {0x00, 0x0000, 0x2000},
+ {0x00, 0x0013, 0x2301},
+ {0x00, 0x0003, 0x2000},
+ {0x00, 0x0001, 0x21ac},
+ {0x00, 0x0001, 0x21a6},
+ {0x00, 0x0000, 0x21a7}, /* brightness */
+ {0x00, 0x0020, 0x21a8}, /* contrast */
+ {0x00, 0x0001, 0x21ac}, /* sat/hue */
+ {0x00, 0x0000, 0x21ad}, /* hue */
+ {0x00, 0x001a, 0x21ae}, /* saturation */
+ {0x00, 0x0002, 0x21a3}, /* gamma */
+ {0x30, 0x0154, 0x0008},
+ {0x30, 0x0004, 0x0006},
+ {0x30, 0x0258, 0x0009},
+ {0x30, 0x0004, 0x0000},
+ {0x30, 0x0093, 0x0004},
+ {0x30, 0x0066, 0x0005},
+ {0x00, 0x0000, 0x2000},
+ {0x00, 0x0013, 0x2301},
+ {0x00, 0x0003, 0x2000},
+ {0x00, 0x0013, 0x2301},
+ {0x00, 0x0003, 0x2000},
+ {}
+};
+
+/* Creative PC-CAM 600 specific open data, sent before using the
+ * generic initialisation data from spca504_open_data.
+ */
+static const __u16 spca504_pccam600_open_data[][3] = {
+ {0x00, 0x0001, 0x2501},
+ {0x20, 0x0500, 0x0001}, /* snapshot mode */
+ {0x00, 0x0003, 0x2880},
+ {0x00, 0x0001, 0x2881},
+ {}
+};
+
+/* Initialisation data for the logitech clicksmart 420 */
+static const __u16 spca504A_clicksmart420_init_data[][3] = {
+/* {0xa0, 0x0000, 0x0503}, * capture mode */
+ {0x00, 0x0000, 0x2000},
+ {0x00, 0x0013, 0x2301},
+ {0x00, 0x0003, 0x2000},
+ {0x00, 0x0001, 0x21ac},
+ {0x00, 0x0001, 0x21a6},
+ {0x00, 0x0000, 0x21a7}, /* brightness */
+ {0x00, 0x0020, 0x21a8}, /* contrast */
+ {0x00, 0x0001, 0x21ac}, /* sat/hue */
+ {0x00, 0x0000, 0x21ad}, /* hue */
+ {0x00, 0x001a, 0x21ae}, /* saturation */
+ {0x00, 0x0002, 0x21a3}, /* gamma */
+ {0x30, 0x0004, 0x000a},
+ {0xb0, 0x0001, 0x0000},
+
+
+ {0x0a1, 0x0080, 0x0001},
+ {0x30, 0x0049, 0x0000},
+ {0x30, 0x0060, 0x0005},
+ {0x0c, 0x0004, 0x0000},
+ {0x00, 0x0000, 0x0000},
+ {0x00, 0x0000, 0x2000},
+ {0x00, 0x0013, 0x2301},
+ {0x00, 0x0003, 0x2000},
+ {0x00, 0x0000, 0x2000},
+
+ {}
+};
+
+/* clicksmart 420 open data ? */
+static const __u16 spca504A_clicksmart420_open_data[][3] = {
+ {0x00, 0x0001, 0x2501},
+ {0x20, 0x0502, 0x0000},
+ {0x06, 0x0000, 0x0000},
+ {0x00, 0x0004, 0x2880},
+ {0x00, 0x0001, 0x2881},
+/* look like setting a qTable */
+ {0x00, 0x0006, 0x2800},
+ {0x00, 0x0004, 0x2801},
+ {0x00, 0x0004, 0x2802},
+ {0x00, 0x0006, 0x2803},
+ {0x00, 0x000a, 0x2804},
+ {0x00, 0x0010, 0x2805},
+ {0x00, 0x0014, 0x2806},
+ {0x00, 0x0018, 0x2807},
+ {0x00, 0x0005, 0x2808},
+ {0x00, 0x0005, 0x2809},
+ {0x00, 0x0006, 0x280a},
+ {0x00, 0x0008, 0x280b},
+ {0x00, 0x000a, 0x280c},
+ {0x00, 0x0017, 0x280d},
+ {0x00, 0x0018, 0x280e},
+ {0x00, 0x0016, 0x280f},
+
+ {0x00, 0x0006, 0x2810},
+ {0x00, 0x0005, 0x2811},
+ {0x00, 0x0006, 0x2812},
+ {0x00, 0x000a, 0x2813},
+ {0x00, 0x0010, 0x2814},
+ {0x00, 0x0017, 0x2815},
+ {0x00, 0x001c, 0x2816},
+ {0x00, 0x0016, 0x2817},
+ {0x00, 0x0006, 0x2818},
+ {0x00, 0x0007, 0x2819},
+ {0x00, 0x0009, 0x281a},
+ {0x00, 0x000c, 0x281b},
+ {0x00, 0x0014, 0x281c},
+ {0x00, 0x0023, 0x281d},
+ {0x00, 0x0020, 0x281e},
+ {0x00, 0x0019, 0x281f},
+
+ {0x00, 0x0007, 0x2820},
+ {0x00, 0x0009, 0x2821},
+ {0x00, 0x000f, 0x2822},
+ {0x00, 0x0016, 0x2823},
+ {0x00, 0x001b, 0x2824},
+ {0x00, 0x002c, 0x2825},
+ {0x00, 0x0029, 0x2826},
+ {0x00, 0x001f, 0x2827},
+ {0x00, 0x000a, 0x2828},
+ {0x00, 0x000e, 0x2829},
+ {0x00, 0x0016, 0x282a},
+ {0x00, 0x001a, 0x282b},
+ {0x00, 0x0020, 0x282c},
+ {0x00, 0x002a, 0x282d},
+ {0x00, 0x002d, 0x282e},
+ {0x00, 0x0025, 0x282f},
+
+ {0x00, 0x0014, 0x2830},
+ {0x00, 0x001a, 0x2831},
+ {0x00, 0x001f, 0x2832},
+ {0x00, 0x0023, 0x2833},
+ {0x00, 0x0029, 0x2834},
+ {0x00, 0x0030, 0x2835},
+ {0x00, 0x0030, 0x2836},
+ {0x00, 0x0028, 0x2837},
+ {0x00, 0x001d, 0x2838},
+ {0x00, 0x0025, 0x2839},
+ {0x00, 0x0026, 0x283a},
+ {0x00, 0x0027, 0x283b},
+ {0x00, 0x002d, 0x283c},
+ {0x00, 0x0028, 0x283d},
+ {0x00, 0x0029, 0x283e},
+ {0x00, 0x0028, 0x283f},
+
+ {0x00, 0x0007, 0x2840},
+ {0x00, 0x0007, 0x2841},
+ {0x00, 0x000a, 0x2842},
+ {0x00, 0x0013, 0x2843},
+ {0x00, 0x0028, 0x2844},
+ {0x00, 0x0028, 0x2845},
+ {0x00, 0x0028, 0x2846},
+ {0x00, 0x0028, 0x2847},
+ {0x00, 0x0007, 0x2848},
+ {0x00, 0x0008, 0x2849},
+ {0x00, 0x000a, 0x284a},
+ {0x00, 0x001a, 0x284b},
+ {0x00, 0x0028, 0x284c},
+ {0x00, 0x0028, 0x284d},
+ {0x00, 0x0028, 0x284e},
+ {0x00, 0x0028, 0x284f},
+
+ {0x00, 0x000a, 0x2850},
+ {0x00, 0x000a, 0x2851},
+ {0x00, 0x0016, 0x2852},
+ {0x00, 0x0028, 0x2853},
+ {0x00, 0x0028, 0x2854},
+ {0x00, 0x0028, 0x2855},
+ {0x00, 0x0028, 0x2856},
+ {0x00, 0x0028, 0x2857},
+ {0x00, 0x0013, 0x2858},
+ {0x00, 0x001a, 0x2859},
+ {0x00, 0x0028, 0x285a},
+ {0x00, 0x0028, 0x285b},
+ {0x00, 0x0028, 0x285c},
+ {0x00, 0x0028, 0x285d},
+ {0x00, 0x0028, 0x285e},
+ {0x00, 0x0028, 0x285f},
+
+ {0x00, 0x0028, 0x2860},
+ {0x00, 0x0028, 0x2861},
+ {0x00, 0x0028, 0x2862},
+ {0x00, 0x0028, 0x2863},
+ {0x00, 0x0028, 0x2864},
+ {0x00, 0x0028, 0x2865},
+ {0x00, 0x0028, 0x2866},
+ {0x00, 0x0028, 0x2867},
+ {0x00, 0x0028, 0x2868},
+ {0x00, 0x0028, 0x2869},
+ {0x00, 0x0028, 0x286a},
+ {0x00, 0x0028, 0x286b},
+ {0x00, 0x0028, 0x286c},
+ {0x00, 0x0028, 0x286d},
+ {0x00, 0x0028, 0x286e},
+ {0x00, 0x0028, 0x286f},
+
+ {0x00, 0x0028, 0x2870},
+ {0x00, 0x0028, 0x2871},
+ {0x00, 0x0028, 0x2872},
+ {0x00, 0x0028, 0x2873},
+ {0x00, 0x0028, 0x2874},
+ {0x00, 0x0028, 0x2875},
+ {0x00, 0x0028, 0x2876},
+ {0x00, 0x0028, 0x2877},
+ {0x00, 0x0028, 0x2878},
+ {0x00, 0x0028, 0x2879},
+ {0x00, 0x0028, 0x287a},
+ {0x00, 0x0028, 0x287b},
+ {0x00, 0x0028, 0x287c},
+ {0x00, 0x0028, 0x287d},
+ {0x00, 0x0028, 0x287e},
+ {0x00, 0x0028, 0x287f},
+
+ {0xa0, 0x0000, 0x0503},
+ {}
+};
+
+static const __u8 qtable_creative_pccam[2][64] = {
+ { /* Q-table Y-components */
+ 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+ 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+ 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+ 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+ 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+ 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+ 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+ 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
+ { /* Q-table C-components */
+ 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+/* FIXME: This Q-table is identical to the Creative PC-CAM one,
+ * except for one byte. Possibly a typo?
+ * NWG: 18/05/2003.
+ */
+static const __u8 qtable_spca504_default[2][64] = {
+ { /* Q-table Y-components */
+ 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+ 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+ 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+ 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+ 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+ 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+ 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+ 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
+ },
+ { /* Q-table C-components */
+ 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+static void reg_r(struct usb_device *dev,
+ __u16 req,
+ __u16 index,
+ __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, buffer, length,
+ 500);
+}
+
+static void reg_w(struct usb_device *dev,
+ __u16 req,
+ __u16 value,
+ __u16 index,
+ __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, buffer, length,
+ 500);
+}
+
+/* write req / index / value */
+static int reg_w_riv(struct usb_device *dev,
+ __u16 req, __u16 index, __u16 value)
+{
+ int ret;
+
+ ret = usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
+ req, index, value, ret);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg write: error %d", ret);
+ return ret;
+}
+
+/* read 1 byte */
+static int reg_r_1(struct gspca_dev *gspca_dev,
+ __u16 value) /* wValue */
+{
+ int ret;
+
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0x20, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value,
+ 0, /* index */
+ gspca_dev->usb_buf, 1,
+ 500); /* timeout */
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_r_1 err %d", ret);
+ return 0;
+ }
+ return gspca_dev->usb_buf[0];
+}
+
+/* read 1 or 2 bytes - returns < 0 if error */
+static int reg_r_12(struct gspca_dev *gspca_dev,
+ __u16 req, /* bRequest */
+ __u16 index, /* wIndex */
+ __u16 length) /* wLength (1 or 2 only) */
+{
+ int ret;
+
+ gspca_dev->usb_buf[1] = 0;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index,
+ gspca_dev->usb_buf, length,
+ 500);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_read err %d", ret);
+ return -1;
+ }
+ return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][3])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, i = 0;
+
+ while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+ ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]);
+ if (ret < 0) {
+ PDEBUG(D_ERR,
+ "Register write failed for 0x%x,0x%x,0x%x",
+ data[i][0], data[i][1], data[i][2]);
+ return ret;
+ }
+ i++;
+ }
+ return 0;
+}
+
+static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
+ unsigned int request,
+ unsigned int ybase,
+ unsigned int cbase,
+ const __u8 qtable[2][64])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int i, err;
+
+ /* loop over y components */
+ for (i = 0; i < 64; i++) {
+ err = reg_w_riv(dev, request, ybase + i, qtable[0][i]);
+ if (err < 0)
+ return err;
+ }
+
+ /* loop over c components */
+ for (i = 0; i < 64; i++) {
+ err = reg_w_riv(dev, request, cbase + i, qtable[1][i]);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
+ __u16 req, __u16 idx, __u16 val)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 notdone;
+
+ reg_w_riv(dev, req, idx, val);
+ notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+ reg_w_riv(dev, req, idx, val);
+
+ PDEBUG(D_FRAM, "before wait 0x%x", notdone);
+
+ msleep(200);
+ notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+ PDEBUG(D_FRAM, "after wait 0x%x", notdone);
+}
+
+static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
+ __u16 req,
+ __u16 idx, __u16 val, __u8 stat, __u8 count)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 status;
+ __u8 endcode;
+
+ reg_w_riv(dev, req, idx, val);
+ status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+ endcode = stat;
+ PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
+ if (!count)
+ return;
+ count = 200;
+ while (--count > 0) {
+ msleep(10);
+ /* gsmart mini2 write a each wait setting 1 ms is enought */
+/* reg_w_riv(dev, req, idx, val); */
+ status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+ if (status == endcode) {
+ PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
+ status, 200 - count);
+ break;
+ }
+ }
+}
+
+static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
+{
+ int count = 10;
+
+ while (--count > 0) {
+ reg_r(gspca_dev->dev, 0x21, 0, gspca_dev->usb_buf, 1);
+ if ((gspca_dev->usb_buf[0] & 0x01) == 0)
+ break;
+ msleep(10);
+ }
+ return gspca_dev->usb_buf[0];
+}
+
+static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int count = 50;
+
+ while (--count > 0) {
+ reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1);
+ if (gspca_dev->usb_buf[0] != 0) {
+ gspca_dev->usb_buf[0] = 0;
+ reg_w(dev, 0x21, 0, 1, gspca_dev->usb_buf, 1);
+ reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1);
+ spca504B_PollingDataReady(gspca_dev);
+ break;
+ }
+ msleep(10);
+ }
+}
+
+static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 *data;
+
+ data = kmalloc(64, GFP_KERNEL);
+ reg_r(dev, 0x20, 0, data, 5);
+ PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
+ data[0], data[1], data[2], data[3], data[4]);
+ reg_r(dev, 0x23, 0, data, 64);
+ reg_r(dev, 0x23, 1, data, 64);
+ kfree(data);
+}
+
+static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 Size;
+ __u8 Type;
+ int rc;
+
+ Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ Type = 0;
+ switch (sd->bridge) {
+ case BRIDGE_SPCA533:
+ reg_w(dev, 0x31, 0, 0, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ rc = spca504B_PollingDataReady(gspca_dev);
+ spca50x_GetFirmware(gspca_dev);
+ gspca_dev->usb_buf[0] = 2; /* type */
+ reg_w(dev, 0x24, 0, 8, gspca_dev->usb_buf, 1);
+ reg_r(dev, 0x24, 8, gspca_dev->usb_buf, 1);
+
+ gspca_dev->usb_buf[0] = Size;
+ reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1);
+ reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1); /* size */
+ rc = spca504B_PollingDataReady(gspca_dev);
+
+ /* Init the cam width height with some values get on init ? */
+ reg_w(dev, 0x31, 0, 4, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ rc = spca504B_PollingDataReady(gspca_dev);
+ break;
+ default:
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA536: */
+ gspca_dev->usb_buf[0] = Size;
+ reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1);
+ reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1); /* size */
+ Type = 6;
+ gspca_dev->usb_buf[0] = Type;
+ reg_w(dev, 0x27, 0, 0, gspca_dev->usb_buf, 1);
+ reg_r(dev, 0x27, 0, gspca_dev->usb_buf, 1); /* type */
+ rc = spca504B_PollingDataReady(gspca_dev);
+ break;
+ case BRIDGE_SPCA504:
+ Size += 3;
+ if (sd->subtype == AiptekMiniPenCam13) {
+ /* spca504a aiptek */
+ spca504A_acknowledged_command(gspca_dev,
+ 0x08, Size, 0,
+ 0x80 | (Size & 0x0f), 1);
+ spca504A_acknowledged_command(gspca_dev,
+ 1, 3, 0, 0x9f, 0);
+ } else {
+ spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
+ }
+ break;
+ case BRIDGE_SPCA504C:
+ /* capture mode */
+ reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
+ reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
+ break;
+ }
+}
+
+static void spca504_wait_status(struct gspca_dev *gspca_dev)
+{
+ int cnt;
+
+ cnt = 256;
+ while (--cnt > 0) {
+ /* With this we get the status, when return 0 it's all ok */
+ if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
+ return;
+ msleep(10);
+ }
+}
+
+static void spca504B_setQtable(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ gspca_dev->usb_buf[0] = 3;
+ reg_w(dev, 0x26, 0, 0, gspca_dev->usb_buf, 1);
+ reg_r(dev, 0x26, 0, gspca_dev->usb_buf, 1);
+ spca504B_PollingDataReady(gspca_dev);
+}
+
+static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int pollreg = 1;
+
+ switch (sd->bridge) {
+ case BRIDGE_SPCA504:
+ case BRIDGE_SPCA504C:
+ pollreg = 0;
+ /* fall thru */
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+ reg_w(dev, 0, 0, 0x21a7, NULL, 0); /* brightness */
+ reg_w(dev, 0, 0x20, 0x21a8, NULL, 0); /* contrast */
+ reg_w(dev, 0, 0, 0x21ad, NULL, 0); /* hue */
+ reg_w(dev, 0, 1, 0x21ac, NULL, 0); /* sat/hue */
+ reg_w(dev, 0, 0x20, 0x21ae, NULL, 0); /* saturation */
+ reg_w(dev, 0, 0, 0x21a3, NULL, 0); /* gamma */
+ break;
+ case BRIDGE_SPCA536:
+ reg_w(dev, 0, 0, 0x20f0, NULL, 0);
+ reg_w(dev, 0, 0x21, 0x20f1, NULL, 0);
+ reg_w(dev, 0, 0x40, 0x20f5, NULL, 0);
+ reg_w(dev, 0, 1, 0x20f4, NULL, 0);
+ reg_w(dev, 0, 0x40, 0x20f6, NULL, 0);
+ reg_w(dev, 0, 0, 0x2089, NULL, 0);
+ break;
+ }
+ if (pollreg)
+ spca504B_PollingDataReady(gspca_dev);
+}
+
+/* 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 usb_device *dev = gspca_dev->dev;
+ struct cam *cam;
+ __u16 vendor;
+ __u16 product;
+ __u8 fw;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ switch (vendor) {
+ case 0x041e: /* Creative cameras */
+/* switch (product) { */
+/* case 0x400b: */
+/* case 0x4012: */
+/* case 0x4013: */
+/* sd->bridge = BRIDGE_SPCA504C; */
+/* break; */
+/* } */
+ break;
+ case 0x0458: /* Genius KYE cameras */
+/* switch (product) { */
+/* case 0x7006: */
+ sd->bridge = BRIDGE_SPCA504B;
+/* break; */
+/* } */
+ break;
+ case 0x0461: /* MicroInnovation */
+/* switch (product) { */
+/* case 0x0821: */
+ sd->bridge = BRIDGE_SPCA533;
+/* break; */
+/* } */
+ break;
+ case 0x046d: /* Logitech Labtec */
+ switch (product) {
+ case 0x0905:
+ sd->subtype = LogitechClickSmart820;
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x0960:
+ sd->subtype = LogitechClickSmart420;
+ sd->bridge = BRIDGE_SPCA504C;
+ break;
+ }
+ break;
+ case 0x0471: /* Philips */
+/* switch (product) { */
+/* case 0x0322: */
+ sd->bridge = BRIDGE_SPCA504B;
+/* break; */
+/* } */
+ break;
+ case 0x04a5: /* Benq */
+ switch (product) {
+ case 0x3003:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ case 0x3008:
+ case 0x300a:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ }
+ break;
+ case 0x04f1: /* JVC */
+/* switch (product) { */
+/* case 0x1001: */
+ sd->bridge = BRIDGE_SPCA504B;
+/* break; */
+/* } */
+ break;
+ case 0x04fc: /* SunPlus */
+ switch (product) {
+ case 0x500c:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ case 0x504a:
+/* try to get the firmware as some cam answer 2.0.1.2.2
+ * and should be a spca504b then overwrite that setting */
+ reg_r(dev, 0x20, 0, gspca_dev->usb_buf, 1);
+ fw = gspca_dev->usb_buf[0];
+ if (fw == 1) {
+ sd->subtype = AiptekMiniPenCam13;
+ sd->bridge = BRIDGE_SPCA504;
+ } else if (fw == 2) {
+ sd->bridge = BRIDGE_SPCA504B;
+ } else
+ return -ENODEV;
+ break;
+ case 0x504b:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ case 0x5330:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x5360:
+ sd->bridge = BRIDGE_SPCA536;
+ break;
+ case 0xffff:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ }
+ break;
+ case 0x052b: /* ?? Megapix */
+/* switch (product) { */
+/* case 0x1513: */
+ sd->subtype = MegapixV4;
+ sd->bridge = BRIDGE_SPCA533;
+/* break; */
+/* } */
+ break;
+ case 0x0546: /* Polaroid */
+ switch (product) {
+ case 0x3155:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x3191:
+ case 0x3273:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ }
+ break;
+ case 0x055f: /* Mustek cameras */
+ switch (product) {
+ case 0xc211:
+ sd->bridge = BRIDGE_SPCA536;
+ break;
+ case 0xc230:
+ case 0xc232:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0xc360:
+ sd->bridge = BRIDGE_SPCA536;
+ break;
+ case 0xc420:
+ sd->bridge = BRIDGE_SPCA504;
+ break;
+ case 0xc430:
+ case 0xc440:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0xc520:
+ sd->bridge = BRIDGE_SPCA504;
+ break;
+ case 0xc530:
+ case 0xc540:
+ case 0xc630:
+ case 0xc650:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ }
+ break;
+ case 0x05da: /* Digital Dream cameras */
+/* switch (product) { */
+/* case 0x1018: */
+ sd->bridge = BRIDGE_SPCA504B;
+/* break; */
+/* } */
+ break;
+ case 0x06d6: /* Trust */
+/* switch (product) { */
+/* case 0x0031: */
+ sd->bridge = BRIDGE_SPCA533; /* SPCA533A */
+/* break; */
+/* } */
+ break;
+ case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+ switch (product) {
+ case 0x1311:
+ case 0x1314:
+ case 0x2211:
+ case 0x2221:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x3261:
+ case 0x3281:
+ sd->bridge = BRIDGE_SPCA536;
+ break;
+ }
+ break;
+ case 0x08ca: /* Aiptek */
+ switch (product) {
+ case 0x0104:
+ case 0x0106:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x2008:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ case 0x2010:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x2016:
+ case 0x2018:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ case 0x2020:
+ case 0x2022:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x2024:
+ sd->bridge = BRIDGE_SPCA536;
+ break;
+ case 0x2028:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x2040:
+ case 0x2042:
+ case 0x2050:
+ case 0x2060:
+ sd->bridge = BRIDGE_SPCA536;
+ break;
+ }
+ break;
+ case 0x0d64: /* SunPlus */
+/* switch (product) { */
+/* case 0x0303: */
+ sd->bridge = BRIDGE_SPCA536;
+/* break; */
+/* } */
+ break;
+ }
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA536: */
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ break;
+ case BRIDGE_SPCA533:
+ cam->cam_mode = custom_mode;
+ cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
+ break;
+ case BRIDGE_SPCA504C:
+ cam->cam_mode = vga_mode2;
+ cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
+ break;
+ }
+ sd->qindex = 5; /* set the quantization table */
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int rc;
+ __u8 i;
+ __u8 info[6];
+ int err_code;
+
+ switch (sd->bridge) {
+ case BRIDGE_SPCA504B:
+ reg_w(dev, 0x1d, 0, 0, NULL, 0);
+ reg_w(dev, 0, 1, 0x2306, NULL, 0);
+ reg_w(dev, 0, 0, 0x0d04, NULL, 0);
+ reg_w(dev, 0, 0, 0x2000, NULL, 0);
+ reg_w(dev, 0, 0x13, 0x2301, NULL, 0);
+ reg_w(dev, 0, 0, 0x2306, NULL, 0);
+ /* fall thru */
+ case BRIDGE_SPCA533:
+ rc = spca504B_PollingDataReady(gspca_dev);
+ spca50x_GetFirmware(gspca_dev);
+ break;
+ case BRIDGE_SPCA536:
+ spca50x_GetFirmware(gspca_dev);
+ reg_r(dev, 0x00, 0x5002, gspca_dev->usb_buf, 1);
+ gspca_dev->usb_buf[0] = 0;
+ reg_w(dev, 0x24, 0, 0, gspca_dev->usb_buf, 1);
+ reg_r(dev, 0x24, 0, gspca_dev->usb_buf, 1);
+ rc = spca504B_PollingDataReady(gspca_dev);
+ reg_w(dev, 0x34, 0, 0, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ break;
+ case BRIDGE_SPCA504C: /* pccam600 */
+ PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
+ reg_w_riv(dev, 0xe0, 0x0000, 0x0000);
+ reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */
+ spca504_wait_status(gspca_dev);
+ if (sd->subtype == LogitechClickSmart420)
+ write_vector(gspca_dev,
+ spca504A_clicksmart420_open_data);
+ else
+ write_vector(gspca_dev, spca504_pccam600_open_data);
+ err_code = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x2800,
+ 0x2840, qtable_creative_pccam);
+ if (err_code < 0) {
+ PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
+ return err_code;
+ }
+ break;
+ default:
+/* case BRIDGE_SPCA504: */
+ PDEBUG(D_STREAM, "Opening SPCA504");
+ if (sd->subtype == AiptekMiniPenCam13) {
+ /*****************************/
+ for (i = 0; i < 6; i++)
+ info[i] = reg_r_1(gspca_dev, i);
+ PDEBUG(D_STREAM,
+ "Read info: %d %d %d %d %d %d."
+ " Should be 1,0,2,2,0,0",
+ info[0], info[1], info[2],
+ info[3], info[4], info[5]);
+ /* spca504a aiptek */
+ /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 8, 3, 0x9e, 1);
+ /* Twice sequencial need status 0xff->0x9e->0x9d */
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 8, 3, 0x9e, 0);
+
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 0, 0, 0x9d, 1);
+ /******************************/
+ /* spca504a aiptek */
+ spca504A_acknowledged_command(gspca_dev, 0x08,
+ 6, 0, 0x86, 1);
+/* reg_write (dev, 0, 0x2000, 0); */
+/* reg_write (dev, 0, 0x2883, 1); */
+/* spca504A_acknowledged_command (gspca_dev, 0x08,
+ 6, 0, 0x86, 1); */
+/* spca504A_acknowledged_command (gspca_dev, 0x24,
+ 0, 0, 0x9D, 1); */
+ reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
+ reg_w_riv(dev, 0x0, 0x2310, 0x05);
+ spca504A_acknowledged_command(gspca_dev, 0x01,
+ 0x0f, 0, 0xff, 0);
+ }
+ /* setup qtable */
+ reg_w_riv(dev, 0, 0x2000, 0);
+ reg_w_riv(dev, 0, 0x2883, 1);
+ err_code = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x2800,
+ 0x2840,
+ qtable_spca504_default);
+ if (err_code < 0) {
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ return err_code;
+ }
+ break;
+ }
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int rc;
+ int enable;
+ __u8 i;
+ __u8 info[6];
+
+ if (sd->bridge == BRIDGE_SPCA504B)
+ spca504B_setQtable(gspca_dev);
+ spca504B_SetSizeType(gspca_dev);
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA536: */
+ if (sd->subtype == MegapixV4 ||
+ sd->subtype == LogitechClickSmart820) {
+ reg_w(dev, 0xf0, 0, 0, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ reg_r(dev, 0xf0, 4, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ } else {
+ reg_w(dev, 0x31, 0, 4, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ rc = spca504B_PollingDataReady(gspca_dev);
+ }
+ break;
+ case BRIDGE_SPCA504:
+ if (sd->subtype == AiptekMiniPenCam13) {
+ for (i = 0; i < 6; i++)
+ info[i] = reg_r_1(gspca_dev, i);
+ PDEBUG(D_STREAM,
+ "Read info: %d %d %d %d %d %d."
+ " Should be 1,0,2,2,0,0",
+ info[0], info[1], info[2],
+ info[3], info[4], info[5]);
+ /* spca504a aiptek */
+ /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 8, 3, 0x9e, 1);
+ /* Twice sequencial need status 0xff->0x9e->0x9d */
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 8, 3, 0x9e, 0);
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 0, 0, 0x9d, 1);
+ } else {
+ spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+ for (i = 0; i < 6; i++)
+ info[i] = reg_r_1(gspca_dev, i);
+ PDEBUG(D_STREAM,
+ "Read info: %d %d %d %d %d %d."
+ " Should be 1,0,2,2,0,0",
+ info[0], info[1], info[2],
+ info[3], info[4], info[5]);
+ spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+ spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
+ }
+ spca504B_SetSizeType(gspca_dev);
+ reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
+ reg_w_riv(dev, 0x0, 0x2310, 0x05);
+ break;
+ case BRIDGE_SPCA504C:
+ if (sd->subtype == LogitechClickSmart420) {
+ write_vector(gspca_dev,
+ spca504A_clicksmart420_init_data);
+ } else {
+ write_vector(gspca_dev, spca504_pccam600_init_data);
+ }
+ enable = (sd->autogain ? 0x04 : 0x01);
+ reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */
+ reg_w_riv(dev, 0xb0, 0x0000, enable); /* auto whiteness */
+
+ /* set default exposure compensation and whiteness balance */
+ reg_w_riv(dev, 0x30, 0x0001, 800); /* ~ 20 fps */
+ reg_w_riv(dev, 0x30, 0x0002, 1600);
+ spca504B_SetSizeType(gspca_dev);
+ break;
+ }
+ sp5xx_initContBrigHueRegisters(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA536: */
+/* case BRIDGE_SPCA504B: */
+ reg_w(dev, 0x31, 0, 0, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ spca504B_PollingDataReady(gspca_dev);
+ break;
+ case BRIDGE_SPCA504:
+ case BRIDGE_SPCA504C:
+ reg_w_riv(dev, 0x00, 0x2000, 0x0000);
+
+ if (sd->subtype == AiptekMiniPenCam13) {
+ /* spca504a aiptek */
+/* spca504A_acknowledged_command(gspca_dev, 0x08,
+ 6, 0, 0x86, 1); */
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 0x00, 0x00, 0x9d, 1);
+ spca504A_acknowledged_command(gspca_dev, 0x01,
+ 0x0f, 0x00, 0xff, 1);
+ } else {
+ spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
+ reg_w_riv(dev, 0x01, 0x000f, 0x00);
+ }
+ break;
+ }
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+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;
+ int i, sof = 0;
+ unsigned char *s, *d;
+ static unsigned char ffd9[] = {0xff, 0xd9};
+
+/* frames are jpeg 4.1.1 without 0xff escape */
+ switch (sd->bridge) {
+ case BRIDGE_SPCA533:
+ if (data[0] == 0xff) {
+ if (data[1] != 0x01) { /* drop packet */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ sof = 1;
+ data += SPCA533_OFFSET_DATA;
+ len -= SPCA533_OFFSET_DATA;
+ } else {
+ data += 1;
+ len -= 1;
+ }
+ break;
+ case BRIDGE_SPCA536:
+ if (data[0] == 0xff) {
+ sof = 1;
+ data += SPCA536_OFFSET_DATA;
+ len -= SPCA536_OFFSET_DATA;
+ } else {
+ data += 2;
+ len -= 2;
+ }
+ break;
+ default:
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504B: */
+ switch (data[0]) {
+ case 0xfe: /* start of frame */
+ sof = 1;
+ data += SPCA50X_OFFSET_DATA;
+ len -= SPCA50X_OFFSET_DATA;
+ break;
+ case 0xff: /* drop packet */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ default:
+ data += 1;
+ len -= 1;
+ break;
+ }
+ break;
+ case BRIDGE_SPCA504C:
+ switch (data[0]) {
+ case 0xfe: /* start of frame */
+ sof = 1;
+ data += SPCA504_PCCAM600_OFFSET_DATA;
+ len -= SPCA504_PCCAM600_OFFSET_DATA;
+ break;
+ case 0xff: /* drop packet */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ default:
+ data += 1;
+ len -= 1;
+ break;
+ }
+ break;
+ }
+ if (sof) { /* start of frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ ffd9, 2);
+
+ /* put the JPEG header in the new frame */
+ jpeg_put_header(gspca_dev, frame,
+ ((struct sd *) gspca_dev)->qindex,
+ 0x22);
+ }
+
+ /* add 0x00 after 0xff */
+ for (i = len; --i >= 0; )
+ if (data[i] == 0xff)
+ break;
+ if (i < 0) { /* no 0xff */
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+ return;
+ }
+ s = data;
+ d = sd->packet;
+ for (i = 0; i < len; i++) {
+ *d++ = *s++;
+ if (s[-1] == 0xff)
+ *d++ = 0x00;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ sd->packet, d - sd->packet);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504C: */
+ reg_w_riv(dev, 0x0, 0x21a7, sd->brightness);
+ break;
+ case BRIDGE_SPCA536:
+ reg_w_riv(dev, 0x0, 0x20f0, sd->brightness);
+ break;
+ }
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u16 brightness = 0;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504C: */
+ brightness = reg_r_12(gspca_dev, 0x00, 0x21a7, 2);
+ break;
+ case BRIDGE_SPCA536:
+ brightness = reg_r_12(gspca_dev, 0x00, 0x20f0, 2);
+ break;
+ }
+ sd->brightness = ((brightness & 0xff) - 128) % 255;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504C: */
+ reg_w_riv(dev, 0x0, 0x21a8, sd->contrast);
+ break;
+ case BRIDGE_SPCA536:
+ reg_w_riv(dev, 0x0, 0x20f1, sd->contrast);
+ break;
+ }
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504C: */
+ sd->contrast = reg_r_12(gspca_dev, 0x00, 0x21a8, 2);
+ break;
+ case BRIDGE_SPCA536:
+ sd->contrast = reg_r_12(gspca_dev, 0x00, 0x20f1, 2);
+ break;
+ }
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504C: */
+ reg_w_riv(dev, 0x0, 0x21ae, sd->colors);
+ break;
+ case BRIDGE_SPCA536:
+ reg_w_riv(dev, 0x0, 0x20f6, sd->colors);
+ break;
+ }
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504C: */
+ sd->colors = reg_r_12(gspca_dev, 0x00, 0x21ae, 2) >> 1;
+ break;
+ case BRIDGE_SPCA536:
+ sd->colors = reg_r_12(gspca_dev, 0x00, 0x20f6, 2) >> 1;
+ break;
+ }
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x400b), DVNM("Creative PC-CAM 600")},
+ {USB_DEVICE(0x041e, 0x4012), DVNM("PC-Cam350")},
+ {USB_DEVICE(0x041e, 0x4013), DVNM("Creative Pccam750")},
+ {USB_DEVICE(0x0458, 0x7006), DVNM("Genius Dsc 1.3 Smart")},
+ {USB_DEVICE(0x0461, 0x0821), DVNM("Fujifilm MV-1")},
+ {USB_DEVICE(0x046d, 0x0905), DVNM("Logitech ClickSmart 820")},
+ {USB_DEVICE(0x046d, 0x0960), DVNM("Logitech ClickSmart 420")},
+ {USB_DEVICE(0x0471, 0x0322), DVNM("Philips DMVC1300K")},
+ {USB_DEVICE(0x04a5, 0x3003), DVNM("Benq DC 1300")},
+ {USB_DEVICE(0x04a5, 0x3008), DVNM("Benq DC 1500")},
+ {USB_DEVICE(0x04a5, 0x300a), DVNM("Benq DC3410")},
+ {USB_DEVICE(0x04f1, 0x1001), DVNM("JVC GC A50")},
+ {USB_DEVICE(0x04fc, 0x500c), DVNM("Sunplus CA500C")},
+ {USB_DEVICE(0x04fc, 0x504a), DVNM("Aiptek Mini PenCam 1.3")},
+ {USB_DEVICE(0x04fc, 0x504b), DVNM("Maxell MaxPocket LE 1.3")},
+ {USB_DEVICE(0x04fc, 0x5330), DVNM("Digitrex 2110")},
+ {USB_DEVICE(0x04fc, 0x5360), DVNM("Sunplus Generic")},
+ {USB_DEVICE(0x04fc, 0xffff), DVNM("Pure DigitalDakota")},
+ {USB_DEVICE(0x052b, 0x1513), DVNM("Megapix V4")},
+ {USB_DEVICE(0x0546, 0x3155), DVNM("Polaroid PDC3070")},
+ {USB_DEVICE(0x0546, 0x3191), DVNM("Polaroid Ion 80")},
+ {USB_DEVICE(0x0546, 0x3273), DVNM("Polaroid PDC2030")},
+ {USB_DEVICE(0x055f, 0xc211), DVNM("Kowa Bs888e Microcamera")},
+ {USB_DEVICE(0x055f, 0xc230), DVNM("Mustek Digicam 330K")},
+ {USB_DEVICE(0x055f, 0xc232), DVNM("Mustek MDC3500")},
+ {USB_DEVICE(0x055f, 0xc360), DVNM("Mustek DV4000 Mpeg4 ")},
+ {USB_DEVICE(0x055f, 0xc420), DVNM("Mustek gSmart Mini 2")},
+ {USB_DEVICE(0x055f, 0xc430), DVNM("Mustek Gsmart LCD 2")},
+ {USB_DEVICE(0x055f, 0xc440), DVNM("Mustek DV 3000")},
+ {USB_DEVICE(0x055f, 0xc520), DVNM("Mustek gSmart Mini 3")},
+ {USB_DEVICE(0x055f, 0xc530), DVNM("Mustek Gsmart LCD 3")},
+ {USB_DEVICE(0x055f, 0xc540), DVNM("Gsmart D30")},
+ {USB_DEVICE(0x055f, 0xc630), DVNM("Mustek MDC4000")},
+ {USB_DEVICE(0x055f, 0xc650), DVNM("Mustek MDC5500Z")},
+ {USB_DEVICE(0x05da, 0x1018), DVNM("Digital Dream Enigma 1.3")},
+ {USB_DEVICE(0x06d6, 0x0031), DVNM("Trust 610 LCD PowerC@m Zoom")},
+ {USB_DEVICE(0x0733, 0x1311), DVNM("Digital Dream Epsilon 1.3")},
+ {USB_DEVICE(0x0733, 0x1314), DVNM("Mercury 2.1MEG Deluxe Classic Cam")},
+ {USB_DEVICE(0x0733, 0x2211), DVNM("Jenoptik jdc 21 LCD")},
+ {USB_DEVICE(0x0733, 0x2221), DVNM("Mercury Digital Pro 3.1p")},
+ {USB_DEVICE(0x0733, 0x3261), DVNM("Concord 3045 spca536a")},
+ {USB_DEVICE(0x0733, 0x3281), DVNM("Cyberpix S550V")},
+ {USB_DEVICE(0x08ca, 0x0104), DVNM("Aiptek PocketDVII 1.3")},
+ {USB_DEVICE(0x08ca, 0x0106), DVNM("Aiptek Pocket DV3100+")},
+ {USB_DEVICE(0x08ca, 0x2008), DVNM("Aiptek Mini PenCam 2 M")},
+ {USB_DEVICE(0x08ca, 0x2010), DVNM("Aiptek PocketCam 3M")},
+ {USB_DEVICE(0x08ca, 0x2016), DVNM("Aiptek PocketCam 2 Mega")},
+ {USB_DEVICE(0x08ca, 0x2018), DVNM("Aiptek Pencam SD 2M")},
+ {USB_DEVICE(0x08ca, 0x2020), DVNM("Aiptek Slim 3000F")},
+ {USB_DEVICE(0x08ca, 0x2022), DVNM("Aiptek Slim 3200")},
+ {USB_DEVICE(0x08ca, 0x2024), DVNM("Aiptek DV3500 Mpeg4 ")},
+ {USB_DEVICE(0x08ca, 0x2028), DVNM("Aiptek PocketCam4M")},
+ {USB_DEVICE(0x08ca, 0x2040), DVNM("Aiptek PocketDV4100M")},
+ {USB_DEVICE(0x08ca, 0x2042), DVNM("Aiptek PocketDV5100")},
+ {USB_DEVICE(0x08ca, 0x2050), DVNM("Medion MD 41437")},
+ {USB_DEVICE(0x08ca, 0x2060), DVNM("Aiptek PocketDV5300")},
+ {USB_DEVICE(0x0d64, 0x0303), DVNM("Sunplus FashionCam DXG")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
new file mode 100644
index 00000000000..00f47e463a0
--- /dev/null
+++ b/drivers/media/video/gspca/t613.c
@@ -0,0 +1,1038 @@
+/*
+ *Notes: * t613 + tas5130A
+ * * Focus to light do not balance well as in win.
+ * Quality in win is not good, but its kinda better.
+ * * Fix some "extraneous bytes", most of apps will show the image anyway
+ * * Gamma table, is there, but its really doing something?
+ * * 7~8 Fps, its ok, max on win its 10.
+ * Costantino Leandro
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "t613"
+#include "gspca.h"
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+#define MAX_GAMMA 0x10 /* 0 to 15 */
+
+/* From LUVCVIEW */
+#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3)
+
+MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
+MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char autogain;
+ unsigned char gamma;
+ unsigned char sharpness;
+ unsigned char freq;
+ unsigned char whitebalance;
+ unsigned char mirror;
+ unsigned char effect;
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 0x0f,
+ .step = 1,
+ .default_value = 0x09,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0x0d,
+ .step = 1,
+ .default_value = 0x07,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_COLOR 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 0x0f,
+ .step = 1,
+ .default_value = 0x05,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+#define SD_GAMMA 3
+ {
+ {
+ .id = V4L2_CID_GAMMA, /* (gamma on win) */
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma (Untested)",
+ .minimum = 0,
+ .maximum = MAX_GAMMA,
+ .step = 1,
+ .default_value = 0x09,
+ },
+ .set = sd_setgamma,
+ .get = sd_getgamma,
+ },
+#define SD_AUTOGAIN 4
+ {
+ {
+ .id = V4L2_CID_GAIN, /* here, i activate only the lowlight,
+ * some apps dont bring up the
+ * backligth_compensation control) */
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Low Light",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0x01,
+ },
+ .set = sd_setlowlight,
+ .get = sd_getlowlight,
+ },
+#define SD_MIRROR 5
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror Image",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = sd_setflip,
+ .get = sd_getflip
+ },
+#define SD_LIGHTFREQ 6
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light Frequency Filter",
+ .minimum = 1, /* 1 -> 0x50, 2->0x60 */
+ .maximum = 2,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq},
+
+#define SD_WHITE_BALANCE 7
+ {
+ {
+ .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setwhitebalance,
+ .get = sd_getwhitebalance
+ },
+#define SD_SHARPNESS 8 /* (aka definition on win) */
+ {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sharpness",
+ .minimum = 0,
+ .maximum = MAX_GAMMA, /* 0 to 16 */
+ .step = 1,
+ .default_value = 0x06,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
+#define SD_EFFECTS 9
+ {
+ {
+ .id = V4L2_CID_EFFECTS,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Webcam Effects",
+ .minimum = 0,
+ .maximum = 4,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = sd_seteffect,
+ .get = sd_geteffect
+ },
+};
+
+static char *effects_control[] = {
+ "Normal",
+ "Emboss", /* disabled */
+ "Monochrome",
+ "Sepia",
+ "Sketch",
+ "Sun Effect", /* disabled */
+ "Negative",
+};
+
+static struct v4l2_pix_format vga_mode_t16[] = {
+ {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 4},
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+#define T16_OFFSET_DATA 631
+#define MAX_EFFECTS 7
+/* easily done by soft, this table could be removed,
+ * i keep it here just in case */
+static const __u8 effects_table[MAX_EFFECTS][6] = {
+ {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
+ {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
+ {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
+ {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */
+ {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */
+ {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */
+ {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
+};
+
+static const __u8 gamma_table[MAX_GAMMA][34] = {
+ {0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,
+ 0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9,
+ 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb,
+ 0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x33, 0x92, 0x5A, 0x93, 0x75,
+ 0x94, 0x85, 0x95, 0x93, 0x96, 0xA1, 0x97, 0xAD,
+ 0x98, 0xB7, 0x99, 0xC2, 0x9A, 0xCB, 0x9B, 0xD4,
+ 0x9C, 0xDE, 0x9D, 0xE7, 0x9E, 0xF0, 0x9F, 0xF7,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x2F, 0x92, 0x51, 0x93, 0x6B,
+ 0x94, 0x7C, 0x95, 0x8A, 0x96, 0x99, 0x97, 0xA6,
+ 0x98, 0xB1, 0x99, 0xBC, 0x9A, 0xC6, 0x9B, 0xD0,
+ 0x9C, 0xDB, 0x9D, 0xE4, 0x9E, 0xED, 0x9F, 0xF6,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,
+ 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9E,
+ 0x98, 0xAA, 0x99, 0xB5, 0x9A, 0xBF, 0x9B, 0xCB,
+ 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x23, 0x92, 0x3F, 0x93, 0x55,
+ 0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95,
+ 0x98, 0xA2, 0x99, 0xAD, 0x9A, 0xB9, 0x9B, 0xC6,
+ 0x9C, 0xD2, 0x9D, 0xDE, 0x9E, 0xE9, 0x9F, 0xF4,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x1B, 0x92, 0x33, 0x93, 0x48,
+ 0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87,
+ 0x98, 0x96, 0x99, 0xA3, 0x9A, 0xB1, 0x9B, 0xBE,
+ 0x9C, 0xCC, 0x9D, 0xDA, 0x9E, 0xE7, 0x9F, 0xF3,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,
+ 0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67,
+ 0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa,
+ 0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,
+ 0x94, 0x38, 0x95, 0x4A, 0x96, 0x60, 0x97, 0x70,
+ 0x98, 0x80, 0x99, 0x90, 0x9A, 0xA0, 0x9B, 0xB0,
+ 0x9C, 0xC0, 0x9D, 0xD0, 0x9E, 0xE0, 0x9F, 0xF0,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,
+ 0x94, 0x47, 0x95, 0x5A, 0x96, 0x69, 0x97, 0x79,
+ 0x98, 0x88, 0x99, 0x97, 0x9A, 0xA7, 0x9B, 0xB6,
+ 0x9C, 0xC4, 0x9D, 0xD3, 0x9E, 0xE0, 0x9F, 0xF0,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,
+ 0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
+ 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd,
+ 0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x18, 0x92, 0x2B, 0x93, 0x44,
+ 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8E,
+ 0x98, 0x9C, 0x99, 0xAA, 0x9A, 0xB7, 0x9B, 0xC4,
+ 0x9C, 0xD0, 0x9D, 0xD8, 0x9E, 0xE2, 0x9F, 0xF0,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x1A, 0x92, 0x34, 0x93, 0x52,
+ 0x94, 0x66, 0x95, 0x7E, 0x96, 0x8D, 0x97, 0x9B,
+ 0x98, 0xA8, 0x99, 0xB4, 0x9A, 0xC0, 0x9B, 0xCB,
+ 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x3F, 0x92, 0x5A, 0x93, 0x6E,
+ 0x94, 0x7F, 0x95, 0x8E, 0x96, 0x9C, 0x97, 0xA8,
+ 0x98, 0xB4, 0x99, 0xBF, 0x9A, 0xC9, 0x9B, 0xD3,
+ 0x9C, 0xDC, 0x9D, 0xE5, 0x9E, 0xEE, 0x9F, 0xF6,
+ 0xA0, 0xFF},
+ {0x90, 0x00, 0x91, 0x54, 0x92, 0x6F, 0x93, 0x83,
+ 0x94, 0x93, 0x95, 0xA0, 0x96, 0xAD, 0x97, 0xB7,
+ 0x98, 0xC2, 0x99, 0xCB, 0x9A, 0xD4, 0x9B, 0xDC,
+ 0x9C, 0xE4, 0x9D, 0xEB, 0x9E, 0xF2, 0x9F, 0xF9,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x6E, 0x92, 0x88, 0x93, 0x9A,
+ 0x94, 0xA8, 0x95, 0xB3, 0x96, 0xBD, 0x97, 0xC6,
+ 0x98, 0xCF, 0x99, 0xD6, 0x9A, 0xDD, 0x9B, 0xE3,
+ 0x9C, 0xE9, 0x9D, 0xEF, 0x9E, 0xF4, 0x9F, 0xFA,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x93, 0x92, 0xA8, 0x93, 0xB7,
+ 0x94, 0xC1, 0x95, 0xCA, 0x96, 0xD2, 0x97, 0xD8,
+ 0x98, 0xDE, 0x99, 0xE3, 0x9A, 0xE8, 0x9B, 0xED,
+ 0x9C, 0xF1, 0x9D, 0xF5, 0x9E, 0xF8, 0x9F, 0xFC,
+ 0xA0, 0xFF}
+};
+
+static const __u8 tas5130a_sensor_init[][8] = {
+ {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
+ {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
+ {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
+ {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
+ {},
+};
+
+/* read 1 byte */
+static int reg_r_1(struct gspca_dev *gspca_dev,
+ __u16 index)
+{
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index,
+ gspca_dev->usb_buf, 1, 500);
+ return gspca_dev->usb_buf[0];
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+ __u16 value,
+ __u16 index,
+ const __u8 *buffer, __u16 len)
+{
+ if (buffer == NULL) {
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index,
+ NULL, 0, 500);
+ return;
+ }
+ if (len <= sizeof gspca_dev->usb_buf) {
+ memcpy(gspca_dev->usb_buf, buffer, len);
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index,
+ gspca_dev->usb_buf, len, 500);
+ } else {
+ __u8 *tmpbuf;
+
+ tmpbuf = kmalloc(len, GFP_KERNEL);
+ memcpy(tmpbuf, buffer, len);
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index,
+ tmpbuf, len, 500);
+ kfree(tmpbuf);
+ }
+}
+
+/* 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;
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+
+ cam->cam_mode = vga_mode_t16;
+ cam->nmodes = ARRAY_SIZE(vga_mode_t16);
+
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+ sd->gamma = sd_ctrls[SD_GAMMA].qctrl.default_value;
+ sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value;
+ sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value;
+ sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value;
+ sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
+ sd->effect = sd_ctrls[SD_EFFECTS].qctrl.default_value;
+ return 0;
+}
+
+static int init_default_parameters(struct gspca_dev *gspca_dev)
+{
+ /* some of this registers are not really neded, because
+ * they are overriden by setbrigthness, setcontrast, etc,
+ * but wont hurt anyway, and can help someone with similar webcam
+ * to see the initial parameters.*/
+ int i = 0;
+ __u8 test_byte;
+
+ static const __u8 read_indexs[] =
+ { 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
+ 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 };
+ static const __u8 n1[6] =
+ {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
+ static const __u8 n2[2] =
+ {0x08, 0x00};
+ static const __u8 nset[6] =
+ { 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
+ static const __u8 n3[6] =
+ {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
+ static const __u8 n4[0x46] =
+ {0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
+ 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
+ 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
+ 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
+ 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
+ 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
+ 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
+ 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
+ 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
+ static const __u8 nset4[18] = {
+ 0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8,
+ 0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
+ 0xe8, 0xe0
+ };
+ /* ojo puede ser 0xe6 en vez de 0xe9 */
+ static const __u8 nset2[20] = {
+ 0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb,
+ 0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
+ 0xd8, 0xc8, 0xd9, 0xfc
+ };
+ static const __u8 missing[8] =
+ { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
+ static const __u8 nset3[18] = {
+ 0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8,
+ 0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
+ 0xcf, 0xe0
+ };
+ static const __u8 nset5[4] =
+ { 0x8f, 0x24, 0xc3, 0x00 }; /* bright */
+ static const __u8 nset6[34] = {
+ 0x90, 0x00, 0x91, 0x1c, 0x92, 0x30, 0x93, 0x43, 0x94, 0x54,
+ 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
+ 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, 0x9c, 0xca,
+ 0x9d, 0xd8, 0x9e, 0xe5, 0x9f, 0xf2,
+ 0xa0, 0xff
+ }; /* Gamma */
+ static const __u8 nset7[4] =
+ { 0x66, 0xca, 0xa8, 0xf8 }; /* 50/60 Hz */
+ static const __u8 nset9[4] =
+ { 0x0b, 0x04, 0x0a, 0x78 };
+ static const __u8 nset8[6] =
+ { 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
+ static const __u8 nset10[6] =
+ { 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 };
+
+ reg_w(gspca_dev, 0x01, 0x0000, n1, 0x06);
+ reg_w(gspca_dev, 0x01, 0x0000, nset, 0x06);
+ reg_r_1(gspca_dev, 0x0063);
+ reg_w(gspca_dev, 0x01, 0x0000, n2, 0x02);
+
+ while (read_indexs[i] != 0x00) {
+ test_byte = reg_r_1(gspca_dev, read_indexs[i]);
+ PDEBUG(D_CONF, "Reg 0x%02x => 0x%02x", read_indexs[i],
+ test_byte);
+ i++;
+ }
+
+ reg_w(gspca_dev, 0x01, 0x0000, n3, 0x06);
+ reg_w(gspca_dev, 0x01, 0x0000, n4, 0x46);
+ reg_r_1(gspca_dev, 0x0080);
+ reg_w(gspca_dev, 0x00, 0x2c80, NULL, 0);
+ reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14);
+ reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12);
+ reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12);
+ reg_w(gspca_dev, 0x00, 0x3880, NULL, 0);
+ reg_w(gspca_dev, 0x00, 0x3880, NULL, 0);
+ reg_w(gspca_dev, 0x00, 0x338e, NULL, 0);
+ reg_w(gspca_dev, 0x01, 0x0000, nset5, 0x04);
+ reg_w(gspca_dev, 0x00, 0x00a9, NULL, 0);
+ reg_w(gspca_dev, 0x01, 0x0000, nset6, 0x22);
+ reg_w(gspca_dev, 0x00, 0x86bb, NULL, 0);
+ reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0);
+
+ reg_w(gspca_dev, 0x01, 0x0000, missing, 0x08);
+
+ reg_w(gspca_dev, 0x00, 0x2087, NULL, 0);
+ reg_w(gspca_dev, 0x00, 0x2088, NULL, 0);
+ reg_w(gspca_dev, 0x00, 0x2089, NULL, 0);
+
+ reg_w(gspca_dev, 0x01, 0x0000, nset7, 0x04);
+ reg_w(gspca_dev, 0x01, 0x0000, nset10, 0x06);
+ reg_w(gspca_dev, 0x01, 0x0000, nset8, 0x06);
+ reg_w(gspca_dev, 0x01, 0x0000, nset9, 0x04);
+
+ reg_w(gspca_dev, 0x00, 0x2880, NULL, 0);
+ reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14);
+ reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12);
+ reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12);
+
+ return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned int brightness;
+ __u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x80 };
+ brightness = sd->brightness;
+
+ if (brightness < 7) {
+ set6[3] = 0x70 - (brightness * 0xa);
+ } else {
+ set6[1] = 0x24;
+ set6[3] = 0x00 + ((brightness - 7) * 0xa);
+ }
+
+ reg_w(gspca_dev, 0x01, 0x0000, set6, 4);
+}
+
+static void setflip(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ __u8 flipcmd[8] =
+ { 0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09 };
+
+ if (sd->mirror == 1)
+ flipcmd[3] = 0x01;
+
+ reg_w(gspca_dev, 0x01, 0x0000, flipcmd, 8);
+}
+
+static void seteffect(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w(gspca_dev, 0x01, 0x0000, effects_table[sd->effect], 0x06);
+ if (sd->effect == 1 || sd->effect == 5) {
+ PDEBUG(D_CONF,
+ "This effect have been disabled for webcam \"safety\"");
+ return;
+ }
+
+ if (sd->effect == 1 || sd->effect == 4)
+ reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0);
+ else
+ reg_w(gspca_dev, 0x00, 0xfaa6, NULL, 0);
+}
+
+static void setwhitebalance(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ __u8 white_balance[8] =
+ { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
+
+ if (sd->whitebalance == 1)
+ white_balance[7] = 0x3c;
+
+ reg_w(gspca_dev, 0x01, 0x0000, white_balance, 8);
+}
+
+static void setlightfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
+
+ if (sd->freq == 2) /* 60hz */
+ freq[1] = 0x00;
+
+ reg_w(gspca_dev, 0x1, 0x0000, freq, 0x4);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned int contrast = sd->contrast;
+ __u16 reg_to_write = 0x00;
+
+ if (contrast < 7)
+ reg_to_write = 0x8ea9 - (0x200 * contrast);
+ else
+ reg_to_write = (0x00a9 + ((contrast - 7) * 0x200));
+
+ reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u16 reg_to_write;
+
+ reg_to_write = 0xc0bb + sd->colors * 0x100;
+ reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
+}
+
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u16 reg_to_write;
+
+ reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
+
+ reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return *val;
+}
+
+static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->whitebalance = val;
+ if (gspca_dev->streaming)
+ setwhitebalance(gspca_dev);
+ return 0;
+}
+
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->whitebalance;
+ return *val;
+}
+
+static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->mirror = val;
+ if (gspca_dev->streaming)
+ setflip(gspca_dev);
+ return 0;
+}
+
+static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->mirror;
+ return *val;
+}
+
+static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->effect = val;
+ if (gspca_dev->streaming)
+ seteffect(gspca_dev);
+ return 0;
+}
+
+static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->effect;
+ return *val;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return *val;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gamma = val;
+ if (gspca_dev->streaming)
+ setgamma(gspca_dev);
+ return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->gamma;
+ return 0;
+}
+
+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)
+ setlightfreq(gspca_dev);
+ return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->freq;
+ return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->sharpness = val;
+ if (gspca_dev->streaming)
+ setsharpness(gspca_dev);
+ return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->sharpness;
+ return 0;
+}
+
+/* Low Light set here......*/
+static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (val != 0)
+ reg_w(gspca_dev, 0x00, 0xf48e, NULL, 0);
+ else
+ reg_w(gspca_dev, 0x00, 0xb48e, NULL, 0);
+ return 0;
+}
+
+static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ int mode;
+
+ static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
+ __u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
+ static const __u8 t3[] =
+ { 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
+ 0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
+ static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
+ switch (mode) {
+ case 1: /* 352x288 */
+ t2[1] = 0x40;
+ break;
+ case 2: /* 320x240 */
+ t2[1] = 0x10;
+ break;
+ case 3: /* 176x144 */
+ t2[1] = 0x50;
+ break;
+ case 4: /* 160x120 */
+ t2[1] = 0x20;
+ break;
+ default: /* 640x480 (0x00) */
+ break;
+ }
+
+ reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[0], 0x8);
+ reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[1], 0x8);
+ reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[2], 0x8);
+ reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
+ reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0);
+ /* just in case and to keep sync with logs (for mine) */
+ reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
+ reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0);
+ /* just in case and to keep sync with logs (for mine) */
+ reg_w(gspca_dev, 0x01, 0x0000, t1, 4);
+ reg_w(gspca_dev, 0x01, 0x0000, t2, 6);
+ reg_r_1(gspca_dev, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0000, t3, 0x10);
+ reg_w(gspca_dev, 0x00, 0x0013, NULL, 0);
+ reg_w(gspca_dev, 0x01, 0x0000, t4, 0x4);
+ /* restart on each start, just in case, sometimes regs goes wrong
+ * when using controls from app */
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ setcolors(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ int sof = 0;
+ static __u8 ffd9[] = { 0xff, 0xd9 };
+
+ if (data[0] == 0x5a) {
+ /* Control Packet, after this came the header again,
+ * but extra bytes came in the packet before this,
+ * sometimes an EOF arrives, sometimes not... */
+ return;
+ }
+
+ if (data[len - 1] == 0xff && data[len] == 0xd9) {
+ /* Just in case, i have seen packets with the marker,
+ * other's do not include it... */
+ data += 2;
+ len -= 4;
+ } else if (data[2] == 0xff && data[3] == 0xd8) {
+ sof = 1;
+ data += 2;
+ len -= 2;
+ } else {
+ data += 2;
+ len -= 2;
+ }
+
+ if (sof) {
+ /* extra bytes....., could be processed too but would be
+ * a waste of time, right now leave the application and
+ * libjpeg do it for ourserlves.. */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ ffd9, 2);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+ return;
+ }
+
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ case V4L2_CID_EFFECTS:
+ if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
+ strncpy((char *) menu->name,
+ effects_control[menu->index], 32);
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ init_default_parameters(gspca_dev);
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x17a1, 0x0128), DVNM("XPX Webcam")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
new file mode 100644
index 00000000000..0b793899095
--- /dev/null
+++ b/drivers/media/video/gspca/tv8532.c
@@ -0,0 +1,670 @@
+/*
+ * Quickcam cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#define MODULE_NAME "tv8532"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("TV8532 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ int buflen; /* current length of tmpbuf */
+ __u8 tmpbuf[352 * 288 + 10 * 288]; /* no protection... */
+ __u8 tmpbuf2[352 * 288]; /* no protection... */
+
+ unsigned short brightness;
+ unsigned short contrast;
+
+ char packet;
+ char synchro;
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 1,
+ .maximum = 0x2ff,
+ .step = 1,
+ .default_value = 0x18f,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0xffff,
+ .step = 1,
+ .default_value = 0x7fff,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+/*
+ * Initialization data: this is the first set-up data written to the
+ * device (before the open data).
+ */
+#define TESTCLK 0x10 /* reg 0x2c -> 0x12 //10 */
+#define TESTCOMP 0x90 /* reg 0x28 -> 0x80 */
+#define TESTLINE 0x81 /* reg 0x29 -> 0x81 */
+#define QCIFLINE 0x41 /* reg 0x29 -> 0x81 */
+#define TESTPTL 0x14 /* reg 0x2D -> 0x14 */
+#define TESTPTH 0x01 /* reg 0x2E -> 0x01 */
+#define TESTPTBL 0x12 /* reg 0x2F -> 0x0a */
+#define TESTPTBH 0x01 /* reg 0x30 -> 0x01 */
+#define ADWIDTHL 0xe8 /* reg 0x0c -> 0xe8 */
+#define ADWIDTHH 0x03 /* reg 0x0d -> 0x03 */
+#define ADHEIGHL 0x90 /* reg 0x0e -> 0x91 //93 */
+#define ADHEIGHH 0x01 /* reg 0x0f -> 0x01 */
+#define EXPOL 0x8f /* reg 0x1c -> 0x8f */
+#define EXPOH 0x01 /* reg 0x1d -> 0x01 */
+#define ADCBEGINL 0x44 /* reg 0x10 -> 0x46 //47 */
+#define ADCBEGINH 0x00 /* reg 0x11 -> 0x00 */
+#define ADRBEGINL 0x0a /* reg 0x14 -> 0x0b //0x0c */
+#define ADRBEGINH 0x00 /* reg 0x15 -> 0x00 */
+#define TV8532_CMD_UPDATE 0x84
+
+#define TV8532_EEprom_Add 0x03
+#define TV8532_EEprom_DataL 0x04
+#define TV8532_EEprom_DataM 0x05
+#define TV8532_EEprom_DataH 0x06
+#define TV8532_EEprom_TableLength 0x07
+#define TV8532_EEprom_Write 0x08
+#define TV8532_PART_CTRL 0x00
+#define TV8532_CTRL 0x01
+#define TV8532_CMD_EEprom_Open 0x30
+#define TV8532_CMD_EEprom_Close 0x29
+#define TV8532_UDP_UPDATE 0x31
+#define TV8532_GPIO 0x39
+#define TV8532_GPIO_OE 0x3B
+#define TV8532_REQ_RegWrite 0x02
+#define TV8532_REQ_RegRead 0x03
+
+#define TV8532_ADWIDTH_L 0x0C
+#define TV8532_ADWIDTH_H 0x0D
+#define TV8532_ADHEIGHT_L 0x0E
+#define TV8532_ADHEIGHT_H 0x0F
+#define TV8532_EXPOSURE 0x1C
+#define TV8532_QUANT_COMP 0x28
+#define TV8532_MODE_PACKET 0x29
+#define TV8532_SETCLK 0x2C
+#define TV8532_POINT_L 0x2D
+#define TV8532_POINT_H 0x2E
+#define TV8532_POINTB_L 0x2F
+#define TV8532_POINTB_H 0x30
+#define TV8532_BUDGET_L 0x2A
+#define TV8532_BUDGET_H 0x2B
+#define TV8532_VID_L 0x34
+#define TV8532_VID_H 0x35
+#define TV8532_PID_L 0x36
+#define TV8532_PID_H 0x37
+#define TV8532_DeviceID 0x83
+#define TV8532_AD_SLOPE 0x91
+#define TV8532_AD_BITCTRL 0x94
+#define TV8532_AD_COLBEGIN_L 0x10
+#define TV8532_AD_COLBEGIN_H 0x11
+#define TV8532_AD_ROWBEGIN_L 0x14
+#define TV8532_AD_ROWBEGIN_H 0x15
+
+static const __u32 tv_8532_eeprom_data[] = {
+/* add dataL dataM dataH */
+ 0x00010001, 0x01018011, 0x02050014, 0x0305001c,
+ 0x040d001e, 0x0505001f, 0x06050519, 0x0705011b,
+ 0x0805091e, 0x090d892e, 0x0a05892f, 0x0b050dd9,
+ 0x0c0509f1, 0
+};
+
+static int reg_r(struct gspca_dev *gspca_dev,
+ __u16 index)
+{
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ TV8532_REQ_RegRead,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, 1,
+ 500);
+ return gspca_dev->usb_buf[0];
+}
+
+/* write 1 byte */
+static void reg_w_1(struct gspca_dev *gspca_dev,
+ __u16 index, __u8 value)
+{
+ gspca_dev->usb_buf[0] = value;
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ TV8532_REQ_RegWrite,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, 1, 500);
+}
+
+/* write 2 bytes */
+static void reg_w_2(struct gspca_dev *gspca_dev,
+ __u16 index, __u8 val1, __u8 val2)
+{
+ gspca_dev->usb_buf[0] = val1;
+ gspca_dev->usb_buf[1] = val2;
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ TV8532_REQ_RegWrite,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, 2, 500);
+}
+
+static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+ __u8 reg, data0, data1, data2;
+
+ reg_w_1(gspca_dev, TV8532_GPIO, 0xb0);
+ reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Open);
+/* msleep(1); */
+ while (tv_8532_eeprom_data[i]) {
+ reg = (tv_8532_eeprom_data[i] & 0xff000000) >> 24;
+ reg_w_1(gspca_dev, TV8532_EEprom_Add, reg);
+ /* msleep(1); */
+ data0 = (tv_8532_eeprom_data[i] & 0x000000ff);
+ reg_w_1(gspca_dev, TV8532_EEprom_DataL, data0);
+ /* msleep(1); */
+ data1 = (tv_8532_eeprom_data[i] & 0x0000ff00) >> 8;
+ reg_w_1(gspca_dev, TV8532_EEprom_DataM, data1);
+ /* msleep(1); */
+ data2 = (tv_8532_eeprom_data[i] & 0x00ff0000) >> 16;
+ reg_w_1(gspca_dev, TV8532_EEprom_DataH, data2);
+ /* msleep(1); */
+ reg_w_1(gspca_dev, TV8532_EEprom_Write, 0);
+ /* msleep(10); */
+ i++;
+ }
+ reg_w_1(gspca_dev, TV8532_EEprom_TableLength, i);
+/* msleep(1); */
+ reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Close);
+ msleep(10);
+}
+
+/* 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;
+
+ tv_8532WriteEEprom(gspca_dev);
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 1;
+ cam->cam_mode = sif_mode;
+ cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ return 0;
+}
+
+static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev)
+{
+ __u8 data;
+
+ data = reg_r(gspca_dev, 0x0001);
+ PDEBUG(D_USBI, "register 0x01-> %x", data);
+ data = reg_r(gspca_dev, 0x0002);
+ PDEBUG(D_USBI, "register 0x02-> %x", data);
+ reg_r(gspca_dev, TV8532_ADWIDTH_L);
+ reg_r(gspca_dev, TV8532_ADWIDTH_H);
+ reg_r(gspca_dev, TV8532_QUANT_COMP);
+ reg_r(gspca_dev, TV8532_MODE_PACKET);
+ reg_r(gspca_dev, TV8532_SETCLK);
+ reg_r(gspca_dev, TV8532_POINT_L);
+ reg_r(gspca_dev, TV8532_POINT_H);
+ reg_r(gspca_dev, TV8532_POINTB_L);
+ reg_r(gspca_dev, TV8532_POINTB_H);
+ reg_r(gspca_dev, TV8532_BUDGET_L);
+ reg_r(gspca_dev, TV8532_BUDGET_H);
+ reg_r(gspca_dev, TV8532_VID_L);
+ reg_r(gspca_dev, TV8532_VID_H);
+ reg_r(gspca_dev, TV8532_PID_L);
+ reg_r(gspca_dev, TV8532_PID_H);
+ reg_r(gspca_dev, TV8532_DeviceID);
+ reg_r(gspca_dev, TV8532_AD_COLBEGIN_L);
+ reg_r(gspca_dev, TV8532_AD_COLBEGIN_H);
+ reg_r(gspca_dev, TV8532_AD_ROWBEGIN_L);
+ reg_r(gspca_dev, TV8532_AD_ROWBEGIN_H);
+}
+
+static void tv_8532_setReg(struct gspca_dev *gspca_dev)
+{
+ reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_L,
+ ADCBEGINL); /* 0x10 */
+ reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H,
+ ADCBEGINH); /* also digital gain */
+ reg_w_1(gspca_dev, TV8532_PART_CTRL,
+ TV8532_CMD_UPDATE); /* 0x00<-0x84 */
+
+ reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0a);
+ /******************************************************/
+ reg_w_1(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL); /* 0e */
+ reg_w_1(gspca_dev, TV8532_ADHEIGHT_H, ADHEIGHH); /* 0f */
+ reg_w_2(gspca_dev, TV8532_EXPOSURE,
+ EXPOL, EXPOH); /* 350d 0x014c; 1c */
+ reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_L,
+ ADCBEGINL); /* 0x10 */
+ reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H,
+ ADCBEGINH); /* also digital gain */
+ reg_w_1(gspca_dev, TV8532_AD_ROWBEGIN_L,
+ ADRBEGINL); /* 0x14 */
+
+ reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x00); /* 0x91 */
+ reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x02); /* 0x94 */
+
+ reg_w_1(gspca_dev, TV8532_CTRL,
+ TV8532_CMD_EEprom_Close); /* 0x01 */
+
+ reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x00); /* 0x91 */
+ reg_w_1(gspca_dev, TV8532_PART_CTRL,
+ TV8532_CMD_UPDATE); /* 0x00<-0x84 */
+}
+
+static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
+{
+ int i;
+
+ /* strange polling from tgc */
+ for (i = 0; i < 10; i++) {
+ reg_w_1(gspca_dev, TV8532_SETCLK,
+ TESTCLK); /* 0x48; //0x08; 0x2c */
+ reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
+ reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01); /* 0x31 */
+ }
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
+ reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
+ tv_8532ReadRegisters(gspca_dev);
+ reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+ reg_w_2(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL,
+ ADHEIGHH); /* 401d 0x0169; 0e */
+ reg_w_2(gspca_dev, TV8532_EXPOSURE, EXPOL,
+ EXPOH); /* 350d 0x014c; 1c */
+ reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL); /* 0x20; 0x0c */
+ reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH); /* 0x0d */
+
+ /*******************************************************************/
+ reg_w_1(gspca_dev, TV8532_QUANT_COMP,
+ TESTCOMP); /* 0x72 compressed mode 0x28 */
+ reg_w_1(gspca_dev, TV8532_MODE_PACKET,
+ TESTLINE); /* 0x84; // CIF | 4 packet 0x29 */
+
+ /************************************************/
+ reg_w_1(gspca_dev, TV8532_SETCLK,
+ TESTCLK); /* 0x48; //0x08; 0x2c */
+ reg_w_1(gspca_dev, TV8532_POINT_L,
+ TESTPTL); /* 0x38; 0x2d */
+ reg_w_1(gspca_dev, TV8532_POINT_H,
+ TESTPTH); /* 0x04; 0x2e */
+ reg_w_1(gspca_dev, TV8532_POINTB_L,
+ TESTPTBL); /* 0x04; 0x2f */
+ reg_w_1(gspca_dev, TV8532_POINTB_H,
+ TESTPTBH); /* 0x04; 0x30 */
+ reg_w_1(gspca_dev, TV8532_PART_CTRL,
+ TV8532_CMD_UPDATE); /* 0x00<-0x84 */
+ /*************************************************/
+ reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01); /* 0x31 */
+ msleep(200);
+ reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */
+ /*************************************************/
+ tv_8532_setReg(gspca_dev);
+ /*************************************************/
+ reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+ /*************************************************/
+ tv_8532_setReg(gspca_dev);
+ /*************************************************/
+ tv_8532_PollReg(gspca_dev);
+ return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int brightness = sd->brightness;
+
+ reg_w_2(gspca_dev, TV8532_EXPOSURE,
+ brightness >> 8, brightness); /* 1c */
+ reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
+ reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
+ tv_8532ReadRegisters(gspca_dev);
+ reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+ reg_w_2(gspca_dev, TV8532_ADHEIGHT_L,
+ ADHEIGHL, ADHEIGHH); /* 401d 0x0169; 0e */
+/* reg_w_2(gspca_dev, TV8532_EXPOSURE,
+ EXPOL, EXPOH); * 350d 0x014c; 1c */
+ setbrightness(gspca_dev);
+
+ reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL); /* 0x20; 0x0c */
+ reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH); /* 0x0d */
+
+ /************************************************/
+ reg_w_1(gspca_dev, TV8532_QUANT_COMP,
+ TESTCOMP); /* 0x72 compressed mode 0x28 */
+ if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ /* 176x144 */
+ reg_w_1(gspca_dev, TV8532_MODE_PACKET,
+ QCIFLINE); /* 0x84; // CIF | 4 packet 0x29 */
+ } else {
+ /* 352x288 */
+ reg_w_1(gspca_dev, TV8532_MODE_PACKET,
+ TESTLINE); /* 0x84; // CIF | 4 packet 0x29 */
+ }
+ /************************************************/
+ reg_w_1(gspca_dev, TV8532_SETCLK,
+ TESTCLK); /* 0x48; //0x08; 0x2c */
+ reg_w_1(gspca_dev, TV8532_POINT_L,
+ TESTPTL); /* 0x38; 0x2d */
+ reg_w_1(gspca_dev, TV8532_POINT_H,
+ TESTPTH); /* 0x04; 0x2e */
+ reg_w_1(gspca_dev, TV8532_POINTB_L,
+ TESTPTBL); /* 0x04; 0x2f */
+ reg_w_1(gspca_dev, TV8532_POINTB_H,
+ TESTPTBH); /* 0x04; 0x30 */
+ reg_w_1(gspca_dev, TV8532_PART_CTRL,
+ TV8532_CMD_UPDATE); /* 0x00<-0x84 */
+ /************************************************/
+ reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01); /* 0x31 */
+ msleep(200);
+ reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */
+ /************************************************/
+ tv_8532_setReg(gspca_dev);
+ /************************************************/
+ reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+ /************************************************/
+ tv_8532_setReg(gspca_dev);
+ /************************************************/
+ tv_8532_PollReg(gspca_dev);
+ reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void tv8532_preprocess(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+/* we should received a whole frame with header and EOL marker
+ * in gspca_dev->tmpbuf and return a GBRG pattern in gspca_dev->tmpbuf2
+ * sequence 2bytes header the Alternate pixels bayer GB 4 bytes
+ * Alternate pixels bayer RG 4 bytes EOL */
+ int width = gspca_dev->width;
+ int height = gspca_dev->height;
+ unsigned char *dst = sd->tmpbuf2;
+ unsigned char *data = sd->tmpbuf;
+ int i;
+
+ /* precompute where is the good bayer line */
+ if (((data[3] + data[width + 7]) >> 1)
+ + (data[4] >> 2)
+ + (data[width + 6] >> 1) >= ((data[2] + data[width + 6]) >> 1)
+ + (data[3] >> 2)
+ + (data[width + 5] >> 1))
+ data += 3;
+ else
+ data += 2;
+ for (i = 0; i < height / 2; i++) {
+ memcpy(dst, data, width);
+ data += width + 3;
+ dst += width;
+ memcpy(dst, data, width);
+ data += width + 7;
+ dst += width;
+ }
+}
+
+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;
+
+ if (data[0] != 0x80) {
+ sd->packet++;
+ if (sd->buflen + len > sizeof sd->tmpbuf) {
+ if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+ PDEBUG(D_PACK, "buffer overflow");
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ }
+ return;
+ }
+ memcpy(&sd->tmpbuf[sd->buflen], data, len);
+ sd->buflen += len;
+ return;
+ }
+
+ /* here we detect 0x80 */
+ /* counter is limited so we need few header for a frame :) */
+
+ /* header 0x80 0x80 0x80 0x80 0x80 */
+ /* packet 00 63 127 145 00 */
+ /* sof 0 1 1 0 0 */
+
+ /* update sequence */
+ if (sd->packet == 63 || sd->packet == 127)
+ sd->synchro = 1;
+
+ /* is there a frame start ? */
+ if (sd->packet >= (gspca_dev->height >> 1) - 1) {
+ PDEBUG(D_PACK, "SOF > %d packet %d", sd->synchro,
+ sd->packet);
+ if (!sd->synchro) { /* start of frame */
+ if (gspca_dev->last_packet_type == FIRST_PACKET) {
+ tv8532_preprocess(gspca_dev);
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame, sd->tmpbuf2,
+ gspca_dev->width *
+ gspca_dev->width);
+ }
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ frame, data, 0);
+ memcpy(sd->tmpbuf, data, len);
+ sd->buflen = len;
+ sd->packet = 0;
+ return;
+ }
+ if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+ PDEBUG(D_PACK,
+ "Warning wrong TV8532 frame detection %d",
+ sd->packet);
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ }
+ return;
+ }
+
+ if (!sd->synchro) {
+ /* Drop packet frame corrupt */
+ PDEBUG(D_PACK, "DROP SOF %d packet %d",
+ sd->synchro, sd->packet);
+ sd->packet = 0;
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
+ sd->synchro = 1;
+ sd->packet++;
+ memcpy(&sd->tmpbuf[sd->buflen], data, len);
+ sd->buflen += len;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x046d, 0x0920), DVNM("QC Express")},
+ {USB_DEVICE(0x046d, 0x0921), DVNM("Labtec Webcam")},
+ {USB_DEVICE(0x0545, 0x808b), DVNM("Veo Stingray")},
+ {USB_DEVICE(0x0545, 0x8333), DVNM("Veo Stingray")},
+ {USB_DEVICE(0x0923, 0x010f), DVNM("ICM532 cams")},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
new file mode 100644
index 00000000000..fcf2c9e3257
--- /dev/null
+++ b/drivers/media/video/gspca/vc032x.c
@@ -0,0 +1,1818 @@
+/*
+ * Z-star vc0321 library
+ * Copyright (C) 2006 Koninski Artur takeshi87@o2.pl
+ * Copyright (C) 2006 Michel Xhaard
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "vc032x"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned char autogain;
+ unsigned char lightfreq;
+
+ char qindex;
+ char bridge;
+#define BRIDGE_VC0321 0
+#define BRIDGE_VC0323 1
+ char sensor;
+#define SENSOR_HV7131R 0
+#define SENSOR_MI1320 1
+#define SENSOR_MI1310_SOC 2
+#define SENSOR_OV7660 3
+#define SENSOR_OV7670 4
+#define SENSOR_PO3130NC 5
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light frequency filter",
+ .minimum = 0,
+ .maximum = 2, /* 0: No, 1: 50Hz, 2:60Hz */
+ .step = 1,
+#define FREQ_DEF 1
+ .default_value = FREQ_DEF,
+ .default_value = 1,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq,
+ },
+};
+
+static struct v4l2_pix_format vc0321_mode[] = {
+ {320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
+ .bytesperline = 320 * 2,
+ .sizeimage = 320 * 240 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
+ .bytesperline = 640 * 2,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+static struct v4l2_pix_format vc0323_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+static const __u8 mi1310_socinitVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x5b, 0x00, 0x01, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x05, 0x00, 0x07, 0xbb},
+ {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb},
+ {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb},
+ {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb},
+ {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb},
+ {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb},
+ {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x2e, 0x0c, 0x55, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb},
+ {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc1, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb},
+ {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb},
+ {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb},
+ {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb},
+ {0x64, 0x7b, 0x5b, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc0, 0xbb},
+ {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc},
+ {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x02, 0xcc},
+ {0xb6, 0x02, 0x80, 0xcc},
+ {0xb6, 0x05, 0x01, 0xcc},
+ {0xb6, 0x04, 0xe0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x25, 0xcc},
+ {0xb6, 0x18, 0x02, 0xcc},
+ {0xb6, 0x17, 0x58, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x00, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb},
+ {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb},
+ {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb},
+ {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb},
+ {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb},
+ {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb},
+ {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb},
+ {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb},
+ {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb},
+ {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb},
+ {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb},
+ {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb},
+ {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb},
+ {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb},
+ {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb},
+ {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb},
+ {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb},
+ {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb},
+ {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xf4, 0x8e, 0xbb},
+ {0x00, 0x00, 0x50, 0xdd},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x24, 0x50, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x34, 0x0c, 0x50, 0xbb},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x03, 0x03, 0xc0, 0xbb},
+ {},
+};
+static const __u8 mi1310_socinitQVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc}, {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc}, {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc}, {0xbc, 0x00, 0xf0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb}, {0x5b, 0x00, 0x01, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x05, 0x00, 0x07, 0xbb}, {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb}, {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb}, {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb}, {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb}, {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb}, {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x2e, 0x0c, 0x55, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc1, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb}, {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb}, {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb}, {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb}, {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb}, {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb}, {0x64, 0x7b, 0x5b, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc0, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc},
+ {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x25, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb}, {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb}, {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb}, {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb}, {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb}, {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb}, {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb}, {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb}, {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb}, {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb}, {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb}, {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb}, {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb}, {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb}, {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb}, {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb}, {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb}, {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb}, {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb}, {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0xf4, 0x8e, 0xbb},
+ {0x00, 0x00, 0x50, 0xdd}, {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x24, 0x50, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x34, 0x0c, 0x50, 0xbb},
+ {0xb3, 0x01, 0x41, 0xcc}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x03, 0x03, 0xc0, 0xbb},
+ {},
+};
+
+static const __u8 mi1320_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const __u8 mi1320_matrix[9] = {
+ 0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52
+};
+static const __u8 mi1320_initVGA_data[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc}, {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x03, 0xcc}, {0xb3, 0x23, 0xc0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc}, {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc}, {0xbc, 0x00, 0xd0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x0d, 0x00, 0x09, 0xbb}, {0x00, 0x01, 0x00, 0xdd},
+ {0x0d, 0x00, 0x08, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
+ {0xa1, 0x05, 0x00, 0xbb}, {0xa4, 0x03, 0xc0, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x9f, 0x0b, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
+ {0x20, 0x01, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
+ {0xf0, 0x00, 0x01, 0xbb}, {0x9d, 0x3c, 0xa0, 0xbb},
+ {0x47, 0x30, 0x30, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x0a, 0x80, 0x11, 0xbb}, {0x35, 0x00, 0x22, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x9d, 0xc5, 0x05, 0xbb},
+ {0xdc, 0x0f, 0xfc, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0x74, 0x0e, 0xbb}, {0x80, 0x00, 0x06, 0xbb},
+ {0x81, 0x04, 0x00, 0xbb}, {0x82, 0x01, 0x02, 0xbb},
+ {0x83, 0x03, 0x02, 0xbb}, {0x84, 0x05, 0x00, 0xbb},
+ {0x85, 0x01, 0x00, 0xbb}, {0x86, 0x03, 0x02, 0xbb},
+ {0x87, 0x05, 0x00, 0xbb}, {0x88, 0x01, 0x00, 0xbb},
+ {0x89, 0x02, 0x02, 0xbb}, {0x8a, 0xfd, 0x04, 0xbb},
+ {0x8b, 0xfc, 0xfd, 0xbb}, {0x8c, 0xff, 0xfd, 0xbb},
+ {0x8d, 0x00, 0x00, 0xbb}, {0x8e, 0xfe, 0x05, 0xbb},
+ {0x8f, 0xfc, 0xfd, 0xbb}, {0x90, 0xfe, 0xfd, 0xbb},
+ {0x91, 0x00, 0x00, 0xbb}, {0x92, 0xfe, 0x03, 0xbb},
+ {0x93, 0xfd, 0xfe, 0xbb}, {0x94, 0xff, 0xfd, 0xbb},
+ {0x95, 0x00, 0x00, 0xbb}, {0xb6, 0x07, 0x05, 0xbb},
+ {0xb7, 0x13, 0x06, 0xbb}, {0xb8, 0x08, 0x06, 0xbb},
+ {0xb9, 0x14, 0x08, 0xbb}, {0xba, 0x06, 0x05, 0xbb},
+ {0xbb, 0x13, 0x06, 0xbb}, {0xbc, 0x03, 0x01, 0xbb},
+ {0xbd, 0x03, 0x04, 0xbb}, {0xbe, 0x00, 0x02, 0xbb},
+ {0xbf, 0x03, 0x01, 0xbb}, {0xc0, 0x02, 0x04, 0xbb},
+ {0xc1, 0x00, 0x04, 0xbb}, {0xc2, 0x02, 0x01, 0xbb},
+ {0xc3, 0x01, 0x03, 0xbb}, {0xc4, 0x00, 0x04, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x05, 0x01, 0x13, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb}, {0x07, 0x00, 0x85, 0xbb},
+ {0x08, 0x00, 0x27, 0xbb}, {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb}, {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb}, {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x39, 0x03, 0x0d, 0xbb},
+ {0x3a, 0x06, 0x1b, 0xbb}, {0x3b, 0x00, 0x95, 0xbb},
+ {0x3c, 0x04, 0xdb, 0xbb}, {0x57, 0x02, 0x00, 0xbb},
+ {0x58, 0x02, 0x66, 0xbb}, {0x59, 0x00, 0xff, 0xbb},
+ {0x5a, 0x01, 0x33, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb}, {0x64, 0x5e, 0x1c, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb},
+ {0x5b, 0x00, 0x01, 0xbb}, {0xf0, 0x00, 0x02, 0xbb},
+ {0x36, 0x68, 0x10, 0xbb}, {0x00, 0x00, 0x30, 0xdd},
+ {0x37, 0x82, 0x00, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x05, 0xcc}, {0xb6, 0x02, 0x00, 0xcc},
+ {0xb6, 0x05, 0x04, 0xcc}, {0xb6, 0x04, 0x00, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x29, 0xcc},
+ {0xb6, 0x18, 0x0a, 0xcc}, {0xb6, 0x17, 0x00, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc}, {0xbf, 0xcc, 0x04, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
+ {}
+};
+static const __u8 mi1320_initQVGA_data[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc}, {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc}, {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd0, 0xcc}, {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x0d, 0x00, 0x09, 0xbb},
+ {0x00, 0x01, 0x00, 0xdd}, {0x0d, 0x00, 0x08, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x02, 0x00, 0x64, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb}, {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb}, {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x00, 0xbb}, {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb}, {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x9d, 0x3c, 0xa0, 0xbb}, {0x47, 0x30, 0x30, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x0a, 0x80, 0x11, 0xbb},
+ {0x35, 0x00, 0x22, 0xbb}, {0xf0, 0x00, 0x02, 0xbb},
+ {0x9d, 0xc5, 0x05, 0xbb}, {0xdc, 0x0f, 0xfc, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0x74, 0x0e, 0xbb},
+ {0x80, 0x00, 0x06, 0xbb}, {0x81, 0x04, 0x00, 0xbb},
+ {0x82, 0x01, 0x02, 0xbb}, {0x83, 0x03, 0x02, 0xbb},
+ {0x84, 0x05, 0x00, 0xbb}, {0x85, 0x01, 0x00, 0xbb},
+ {0x86, 0x03, 0x02, 0xbb}, {0x87, 0x05, 0x00, 0xbb},
+ {0x88, 0x01, 0x00, 0xbb}, {0x89, 0x02, 0x02, 0xbb},
+ {0x8a, 0xfd, 0x04, 0xbb}, {0x8b, 0xfc, 0xfd, 0xbb},
+ {0x8c, 0xff, 0xfd, 0xbb}, {0x8d, 0x00, 0x00, 0xbb},
+ {0x8e, 0xfe, 0x05, 0xbb}, {0x8f, 0xfc, 0xfd, 0xbb},
+ {0x90, 0xfe, 0xfd, 0xbb}, {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xfe, 0x03, 0xbb}, {0x93, 0xfd, 0xfe, 0xbb},
+ {0x94, 0xff, 0xfd, 0xbb}, {0x95, 0x00, 0x00, 0xbb},
+ {0xb6, 0x07, 0x05, 0xbb}, {0xb7, 0x13, 0x06, 0xbb},
+ {0xb8, 0x08, 0x06, 0xbb}, {0xb9, 0x14, 0x08, 0xbb},
+ {0xba, 0x06, 0x05, 0xbb}, {0xbb, 0x13, 0x06, 0xbb},
+ {0xbc, 0x03, 0x01, 0xbb}, {0xbd, 0x03, 0x04, 0xbb},
+ {0xbe, 0x00, 0x02, 0xbb}, {0xbf, 0x03, 0x01, 0xbb},
+ {0xc0, 0x02, 0x04, 0xbb}, {0xc1, 0x00, 0x04, 0xbb},
+ {0xc2, 0x02, 0x01, 0xbb}, {0xc3, 0x01, 0x03, 0xbb},
+ {0xc4, 0x00, 0x04, 0xbb}, {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x00, 0x00, 0xbb}, {0x2e, 0x00, 0x00, 0xbb},
+ {0x2e, 0x0c, 0x5b, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb}, {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb}, {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb}, {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb}, {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb}, {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb}, {0x5b, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x68, 0x10, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd}, {0x37, 0x81, 0x00, 0xbb},
+ {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
+ {0xbf, 0xc0, 0x26, 0xcc}, {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc}, {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {}
+};
+
+static const __u8 po3130_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const __u8 po3130_matrix[9] = {
+ 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
+};
+
+static const __u8 po3130_initVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc},
+ {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe8, 0xcc}, {0xb8, 0x08, 0xe8, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0xf6, 0xcc},
+ {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0x71, 0xcc},
+ {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
+ {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa},
+ {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa},
+ {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa},
+ {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa},
+ {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa},
+ {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa},
+ {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa},
+ {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa},
+ {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x5a, 0x04, 0xaa},
+ {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa},
+ {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa},
+ {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa},
+ {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa},
+ {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa},
+ {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa},
+ {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa},
+ {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa},
+ {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa},
+ {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa},
+ {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa},
+ {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa},
+ {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa},
+ {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa},
+ {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa},
+ {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa},
+ {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
+ {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa},
+ {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa},
+ {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa},
+ {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa},
+ {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa},
+ {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa},
+ {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa},
+ {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
+ {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa},
+ {0x00, 0x4c, 0x07, 0xaa},
+ {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa},
+ {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa},
+/* {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa},
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, */
+ {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0x20, 0xc4, 0xaa},
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc}, {0x00, 0x05, 0x00, 0xaa},
+ {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
+ {}
+};
+static const __u8 po3130_rundata[][4] = {
+ {0x00, 0x47, 0x45, 0xaa}, {0x00, 0x48, 0x9b, 0xaa},
+ {0x00, 0x49, 0x3a, 0xaa}, {0x00, 0x4a, 0x01, 0xaa},
+ {0x00, 0x44, 0x40, 0xaa},
+/* {0x00, 0xd5, 0x7c, 0xaa}, */
+ {0x00, 0xad, 0x04, 0xaa}, {0x00, 0xae, 0x00, 0xaa},
+ {0x00, 0xb0, 0x78, 0xaa}, {0x00, 0x98, 0x02, 0xaa},
+ {0x00, 0x94, 0x25, 0xaa}, {0x00, 0x95, 0x25, 0xaa},
+ {0x00, 0x59, 0x68, 0xaa}, {0x00, 0x44, 0x20, 0xaa},
+ {0x00, 0x17, 0x50, 0xaa}, {0x00, 0x19, 0x50, 0xaa},
+ {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0xd1, 0x3c, 0xaa},
+ {0x00, 0x1e, 0x06, 0xaa}, {0x00, 0x1e, 0x06, 0xaa},
+ {}
+};
+
+static const __u8 po3130_initQVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x09, 0xcc},
+ {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc},
+ {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xb8, 0x08, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0xf6, 0xcc},
+ {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc},
+ {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
+ {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa},
+ {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa},
+ {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa},
+ {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa},
+ {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa},
+ {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa},
+ {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa},
+ {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa},
+ {0x00, 0x59, 0x6f, 0xaa}, {0x00, 0x5a, 0x04, 0xaa},
+ {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa},
+ {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa},
+ {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa},
+ {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa},
+ {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa},
+ {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa},
+ {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa},
+ {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa},
+ {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa},
+ {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa},
+ {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa},
+ {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa},
+ {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa},
+ {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa},
+ {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa},
+ {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa},
+ {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
+ {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa},
+ {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa},
+ {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa},
+ {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa},
+ {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa},
+ {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa},
+ {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa},
+ {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
+ {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0x4c, 0x07, 0xaa},
+ {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa},
+ {0x00, 0x59, 0x66, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa},
+ {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa},
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc}, {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc}, {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc}, {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc}, {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc}, {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc}, {0x00, 0x05, 0x00, 0xaa},
+ {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
+ {}
+};
+
+static const __u8 hv7131r_gamma[17] = {
+/* 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ * 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff */
+ 0x04, 0x1a, 0x36, 0x55, 0x6f, 0x87, 0x9d, 0xb0, 0xc1,
+ 0xcf, 0xda, 0xe4, 0xec, 0xf3, 0xf8, 0xfd, 0xff
+};
+static const __u8 hv7131r_matrix[9] = {
+ 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
+};
+static const __u8 hv7131r_initVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x01, 0x45, 0xcc}, {0xb3, 0x03, 0x0b, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc}, {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0x91, 0xcc}, {0xb3, 0x00, 0x27, 0xcc},
+ {0xbc, 0x00, 0x73, 0xcc},
+ {0xb8, 0x00, 0x23, 0xcc}, {0x00, 0x01, 0x0c, 0xaa},
+ {0x00, 0x14, 0x01, 0xaa}, {0x00, 0x15, 0xe6, 0xaa},
+ {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x17, 0x86, 0xaa}, {0x00, 0x23, 0x00, 0xaa},
+ {0x00, 0x25, 0x09, 0xaa}, {0x00, 0x26, 0x27, 0xaa},
+ {0x00, 0x27, 0xc0, 0xaa},
+ {0xb8, 0x2c, 0x60, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc},
+ {0xb8, 0x31, 0xf8, 0xcc}, {0xb8, 0x32, 0xf8, 0xcc},
+ {0xb8, 0x33, 0xf8, 0xcc}, {0xb8, 0x34, 0x65, 0xcc},
+ {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x01, 0x7d, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc}, {0xb8, 0xfe, 0x00, 0xcc},
+ {0xb8, 0xff, 0x28, 0xcc}, {0xb9, 0x00, 0x28, 0xcc},
+ {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc},
+ {0xb9, 0x07, 0x3c, 0xcc}, {0xb9, 0x08, 0x3c, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
+ {0x00, 0x30, 0x18, 0xaa},
+ {}
+};
+
+static const __u8 hv7131r_initQVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x03, 0x0b, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0x91, 0xcc},
+ {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc},
+ {0xb8, 0x00, 0x21, 0xcc},
+ {0x00, 0x01, 0x0c, 0xaa}, {0x00, 0x14, 0x01, 0xaa},
+ {0x00, 0x15, 0xe6, 0xaa}, {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x17, 0x86, 0xaa},
+ {0x00, 0x23, 0x00, 0xaa}, {0x00, 0x25, 0x01, 0xaa},
+ {0x00, 0x26, 0xd4, 0xaa}, {0x00, 0x27, 0xc0, 0xaa},
+ {0xbc, 0x02, 0x08, 0xcc},
+ {0xbc, 0x03, 0x70, 0xcc}, {0xbc, 0x04, 0x08, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc}, {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x3c, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x04, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb8, 0xfe, 0x02, 0xcc},
+ {0xb8, 0xff, 0x07, 0xcc}, {0xb9, 0x00, 0x14, 0xcc},
+ {0xb9, 0x01, 0x14, 0xcc}, {0xb9, 0x02, 0x14, 0xcc},
+ {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x02, 0xcc}, {0xb9, 0x05, 0x05, 0xcc},
+ {0xb9, 0x06, 0x0f, 0xcc}, {0xb9, 0x07, 0x0f, 0xcc},
+ {0xb9, 0x08, 0x0f, 0xcc},
+ {0xb8, 0x2c, 0x60, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc},
+ {0xb8, 0x31, 0xf8, 0xcc}, {0xb8, 0x32, 0xf8, 0xcc},
+ {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x65, 0xcc}, {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x01, 0x7d, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc}, {0xb8, 0xfe, 0x00, 0xcc},
+ {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc},
+ {0xb9, 0x05, 0x3c, 0xcc}, {0xb9, 0x06, 0x3c, 0xcc},
+ {0xb9, 0x07, 0x3c, 0xcc}, {0xb9, 0x08, 0x3c, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc}, {0x00, 0x30, 0x18, 0xaa},
+ {}
+};
+
+static const __u8 ov7660_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const __u8 ov7660_matrix[9] = {
+ 0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62
+};
+static const __u8 ov7660_initVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd},
+ {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc},
+ {0xb3, 0x1f, 0x02, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
+ {0xb8, 0x00, 0x33, 0xcc}, /* 13 */
+ {0xb8, 0x01, 0x7d, 0xcc},
+ {0xbc, 0x00, 0x73, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x8f, 0x50, 0xcc},
+ {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa},
+ {0x00, 0x12, 0x80, 0xaa},
+ {0x00, 0x12, 0x05, 0xaa},
+ {0x00, 0x1e, 0x01, 0xaa},
+ {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
+ {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
+ {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa},
+ {0x00, 0x13, 0xa7, 0xaa},
+ {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa},
+ {0x00, 0x36, 0x00, 0xaa},
+ {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa},
+ {0x00, 0x39, 0x43, 0xaa},
+ {0x00, 0x8d, 0xcf, 0xaa},
+ {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa},
+ {0x00, 0x0f, 0x62, 0xaa},
+ {0x00, 0x35, 0x84, 0xaa},
+ {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */
+ {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
+ {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
+ {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc},
+ {0x00, 0x01, 0x80, 0xaa},
+ {0x00, 0x02, 0x80, 0xaa},
+ {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc},
+ {0xb9, 0x01, 0x28, 0xcc}, {0xb9, 0x02, 0x28, 0xcc},
+ {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc},
+ {0xb9, 0x05, 0x3c, 0xcc}, {0xb9, 0x06, 0x3c, 0xcc},
+ {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc},
+
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
+
+ {0x00, 0x29, 0x3c, 0xaa}, {0xb3, 0x01, 0x45, 0xcc},
+ {}
+};
+static const __u8 ov7660_initQVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc},
+ {0xb3, 0x1f, 0x02, 0xcc}, {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
+ {0xb8, 0x00, 0x33, 0xcc}, /* 13 */
+ {0xb8, 0x01, 0x7d, 0xcc},
+/* sizer */
+ {0xbc, 0x00, 0xd3, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x8f, 0x50, 0xcc},
+ {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa},
+ {0x00, 0x12, 0x80, 0xaa}, {0x00, 0x12, 0x05, 0xaa},
+ {0x00, 0x1e, 0x01, 0xaa},
+ {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
+ {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
+ {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa},
+ {0x00, 0x13, 0xa7, 0xaa},
+ {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa},
+ {0x00, 0x36, 0x00, 0xaa},
+ {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa},
+ {0x00, 0x39, 0x43, 0xaa}, {0x00, 0x8d, 0xcf, 0xaa},
+ {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa},
+ {0x00, 0x0f, 0x62, 0xaa}, {0x00, 0x35, 0x84, 0xaa},
+ {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */
+ {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
+ {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
+ {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc},
+ {0x00, 0x01, 0x80, 0xaa},
+ {0x00, 0x02, 0x80, 0xaa},
+/* sizer filters */
+ {0xbc, 0x02, 0x08, 0xcc},
+ {0xbc, 0x03, 0x70, 0xcc},
+ {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc},
+ {0xb8, 0x37, 0x00, 0xcc},
+ {0xbc, 0x04, 0x08, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x3c, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x04, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+/* */
+ {0xb8, 0xfe, 0x00, 0xcc},
+ {0xb8, 0xff, 0x28, 0xcc},
+/* */
+ {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc},
+/* */
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc}, /* ff */
+ {0x00, 0x29, 0x3c, 0xaa},
+ {0xb3, 0x01, 0x45, 0xcc}, /* 45 */
+ {}
+};
+
+static const __u8 ov7660_50HZ[][4] = {
+ {0x00, 0x3b, 0x08, 0xaa},
+ {0x00, 0x9d, 0x40, 0xaa},
+ {0x00, 0x13, 0xa7, 0xaa},
+ {}
+};
+
+static const __u8 ov7660_60HZ[][4] = {
+ {0x00, 0x3b, 0x00, 0xaa},
+ {0x00, 0x9e, 0x40, 0xaa},
+ {0x00, 0x13, 0xa7, 0xaa},
+ {}
+};
+
+static const __u8 ov7660_NoFliker[][4] = {
+ {0x00, 0x13, 0x87, 0xaa},
+ {}
+};
+
+static const __u8 ov7670_initVGA_JPG[][4] = {
+ {0xb3, 0x01, 0x05, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd}, {0xb0, 0x03, 0x19, 0xcc},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x10, 0xdd},
+ {0xb3, 0x00, 0x66, 0xcc}, {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc}, {0xb3, 0x03, 0x1f, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xbc, 0x00, 0x41, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc}, {0x00, 0x12, 0x80, 0xaa},
+ {0x00, 0x00, 0x20, 0xdd}, {0x00, 0x12, 0x00, 0xaa},
+ {0x00, 0x11, 0x40, 0xaa}, {0x00, 0x6b, 0x0a, 0xaa},
+ {0x00, 0x3a, 0x04, 0xaa}, {0x00, 0x40, 0xc0, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa}, {0x00, 0x7a, 0x29, 0xaa},
+ {0x00, 0x7b, 0x0e, 0xaa}, {0x00, 0x7c, 0x1a, 0xaa},
+ {0x00, 0x7d, 0x31, 0xaa}, {0x00, 0x7e, 0x53, 0xaa},
+ {0x00, 0x7f, 0x60, 0xaa}, {0x00, 0x80, 0x6b, 0xaa},
+ {0x00, 0x81, 0x73, 0xaa}, {0x00, 0x82, 0x7b, 0xaa},
+ {0x00, 0x83, 0x82, 0xaa}, {0x00, 0x84, 0x89, 0xaa},
+ {0x00, 0x85, 0x96, 0xaa}, {0x00, 0x86, 0xa1, 0xaa},
+ {0x00, 0x87, 0xb7, 0xaa}, {0x00, 0x88, 0xcc, 0xaa},
+ {0x00, 0x89, 0xe1, 0xaa}, {0x00, 0x13, 0xe0, 0xaa},
+ {0x00, 0x00, 0x00, 0xaa}, {0x00, 0x10, 0x00, 0xaa},
+ {0x00, 0x0d, 0x40, 0xaa}, {0x00, 0x14, 0x28, 0xaa},
+ {0x00, 0xa5, 0x05, 0xaa}, {0x00, 0xab, 0x07, 0xaa},
+ {0x00, 0x24, 0x95, 0xaa}, {0x00, 0x25, 0x33, 0xaa},
+ {0x00, 0x26, 0xe3, 0xaa}, {0x00, 0x9f, 0x88, 0xaa},
+ {0x00, 0xa0, 0x78, 0xaa}, {0x00, 0x55, 0x90, 0xaa},
+ {0x00, 0xa1, 0x03, 0xaa}, {0x00, 0xa6, 0xe0, 0xaa},
+ {0x00, 0xa7, 0xd8, 0xaa}, {0x00, 0xa8, 0xf0, 0xaa},
+ {0x00, 0xa9, 0x90, 0xaa}, {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x13, 0xe5, 0xaa}, {0x00, 0x0e, 0x61, 0xaa},
+ {0x00, 0x0f, 0x4b, 0xaa}, {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x1e, 0x07, 0xaa}, {0x00, 0x21, 0x02, 0xaa},
+ {0x00, 0x22, 0x91, 0xaa}, {0x00, 0x29, 0x07, 0xaa},
+ {0x00, 0x33, 0x0b, 0xaa}, {0x00, 0x35, 0x0b, 0xaa},
+ {0x00, 0x37, 0x1d, 0xaa}, {0x00, 0x38, 0x71, 0xaa},
+ {0x00, 0x39, 0x2a, 0xaa}, {0x00, 0x3c, 0x78, 0xaa},
+ {0x00, 0x4d, 0x40, 0xaa}, {0x00, 0x4e, 0x20, 0xaa},
+ {0x00, 0x74, 0x19, 0xaa}, {0x00, 0x8d, 0x4f, 0xaa},
+ {0x00, 0x8e, 0x00, 0xaa}, {0x00, 0x8f, 0x00, 0xaa},
+ {0x00, 0x90, 0x00, 0xaa}, {0x00, 0x91, 0x00, 0xaa},
+ {0x00, 0x96, 0x00, 0xaa}, {0x00, 0x9a, 0x80, 0xaa},
+ {0x00, 0xb0, 0x84, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa},
+ {0x00, 0xb2, 0x0e, 0xaa}, {0x00, 0xb3, 0x82, 0xaa},
+ {0x00, 0xb8, 0x0a, 0xaa}, {0x00, 0x43, 0x14, 0xaa},
+ {0x00, 0x44, 0xf0, 0xaa}, {0x00, 0x45, 0x45, 0xaa},
+ {0x00, 0x46, 0x63, 0xaa}, {0x00, 0x47, 0x2d, 0xaa},
+ {0x00, 0x48, 0x46, 0xaa}, {0x00, 0x59, 0x88, 0xaa},
+ {0x00, 0x5a, 0xa0, 0xaa}, {0x00, 0x5b, 0xc6, 0xaa},
+ {0x00, 0x5c, 0x7d, 0xaa}, {0x00, 0x5d, 0x5f, 0xaa},
+ {0x00, 0x5e, 0x19, 0xaa}, {0x00, 0x6c, 0x0a, 0xaa},
+ {0x00, 0x6d, 0x55, 0xaa}, {0x00, 0x6e, 0x11, 0xaa},
+ {0x00, 0x6f, 0x9e, 0xaa}, {0x00, 0x69, 0x00, 0xaa},
+ {0x00, 0x6a, 0x40, 0xaa}, {0x00, 0x01, 0x40, 0xaa},
+ {0x00, 0x02, 0x40, 0xaa}, {0x00, 0x13, 0xe7, 0xaa},
+ {0x00, 0x5f, 0xf0, 0xaa}, {0x00, 0x60, 0xf0, 0xaa},
+ {0x00, 0x61, 0xf0, 0xaa}, {0x00, 0x27, 0xa0, 0xaa},
+ {0x00, 0x28, 0x80, 0xaa}, {0x00, 0x2c, 0x90, 0xaa},
+ {0x00, 0x4f, 0x66, 0xaa}, {0x00, 0x50, 0x66, 0xaa},
+ {0x00, 0x51, 0x00, 0xaa}, {0x00, 0x52, 0x22, 0xaa},
+ {0x00, 0x53, 0x5e, 0xaa}, {0x00, 0x54, 0x80, 0xaa},
+ {0x00, 0x58, 0x9e, 0xaa}, {0x00, 0x41, 0x08, 0xaa},
+ {0x00, 0x3f, 0x00, 0xaa}, {0x00, 0x75, 0x85, 0xaa},
+ {0x00, 0x76, 0xe1, 0xaa}, {0x00, 0x4c, 0x00, 0xaa},
+ {0x00, 0x77, 0x0a, 0xaa}, {0x00, 0x3d, 0x88, 0xaa},
+ {0x00, 0x4b, 0x09, 0xaa}, {0x00, 0xc9, 0x60, 0xaa},
+ {0x00, 0x41, 0x38, 0xaa}, {0x00, 0x62, 0x30, 0xaa},
+ {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x64, 0x08, 0xaa},
+ {0x00, 0x94, 0x07, 0xaa}, {0x00, 0x95, 0x0b, 0xaa},
+ {0x00, 0x65, 0x00, 0xaa}, {0x00, 0x66, 0x05, 0xaa},
+ {0x00, 0x56, 0x50, 0xaa}, {0x00, 0x34, 0x11, 0xaa},
+ {0x00, 0xa4, 0x88, 0xaa}, {0x00, 0x96, 0x00, 0xaa},
+ {0x00, 0x97, 0x30, 0xaa}, {0x00, 0x98, 0x20, 0xaa},
+ {0x00, 0x99, 0x30, 0xaa}, {0x00, 0x9a, 0x84, 0xaa},
+ {0x00, 0x9b, 0x29, 0xaa}, {0x00, 0x9c, 0x03, 0xaa},
+ {0x00, 0x78, 0x04, 0xaa}, {0x00, 0x79, 0x01, 0xaa},
+ {0x00, 0xc8, 0xf0, 0xaa}, {0x00, 0x79, 0x0f, 0xaa},
+ {0x00, 0xc8, 0x00, 0xaa}, {0x00, 0x79, 0x10, 0xaa},
+ {0x00, 0xc8, 0x7e, 0xaa}, {0x00, 0x79, 0x0a, 0xaa},
+ {0x00, 0xc8, 0x80, 0xaa}, {0x00, 0x79, 0x0b, 0xaa},
+ {0x00, 0xc8, 0x01, 0xaa}, {0x00, 0x79, 0x0c, 0xaa},
+ {0x00, 0xc8, 0x0f, 0xaa}, {0x00, 0x79, 0x0d, 0xaa},
+ {0x00, 0xc8, 0x20, 0xaa}, {0x00, 0x79, 0x09, 0xaa},
+ {0x00, 0xc8, 0x80, 0xaa}, {0x00, 0x79, 0x02, 0xaa},
+ {0x00, 0xc8, 0xc0, 0xaa}, {0x00, 0x79, 0x03, 0xaa},
+ {0x00, 0xc8, 0x40, 0xaa}, {0x00, 0x79, 0x05, 0xaa},
+ {0x00, 0xc8, 0x30, 0xaa}, {0x00, 0x79, 0x26, 0xaa},
+ {0x00, 0x11, 0x40, 0xaa}, {0x00, 0x3a, 0x04, 0xaa},
+ {0x00, 0x12, 0x00, 0xaa}, {0x00, 0x40, 0xc0, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa}, {0x00, 0x17, 0x14, 0xaa},
+ {0x00, 0x18, 0x02, 0xaa}, {0x00, 0x32, 0x92, 0xaa},
+ {0x00, 0x19, 0x02, 0xaa}, {0x00, 0x1a, 0x7a, 0xaa},
+ {0x00, 0x03, 0x0a, 0xaa}, {0x00, 0x0c, 0x00, 0xaa},
+ {0x00, 0x3e, 0x00, 0xaa}, {0x00, 0x70, 0x3a, 0xaa},
+ {0x00, 0x71, 0x35, 0xaa}, {0x00, 0x72, 0x11, 0xaa},
+ {0x00, 0x73, 0xf0, 0xaa}, {0x00, 0xa2, 0x02, 0xaa},
+ {0x00, 0xb1, 0x00, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa},
+ {0x00, 0x1e, 0x37, 0xaa}, {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x24, 0x80, 0xaa}, {0x00, 0x25, 0x74, 0xaa},
+ {0x00, 0x26, 0xd3, 0xaa}, {0x00, 0x0d, 0x00, 0xaa},
+ {0x00, 0x14, 0x18, 0xaa}, {0x00, 0x9d, 0x99, 0xaa},
+ {0x00, 0x9e, 0x7f, 0xaa}, {0x00, 0x64, 0x08, 0xaa},
+ {0x00, 0x94, 0x07, 0xaa}, {0x00, 0x95, 0x06, 0xaa},
+ {0x00, 0x66, 0x05, 0xaa}, {0x00, 0x41, 0x08, 0xaa},
+ {0x00, 0x3f, 0x00, 0xaa}, {0x00, 0x75, 0x07, 0xaa},
+ {0x00, 0x76, 0xe1, 0xaa}, {0x00, 0x4c, 0x00, 0xaa},
+ {0x00, 0x77, 0x00, 0xaa}, {0x00, 0x3d, 0xc2, 0xaa},
+ {0x00, 0x4b, 0x09, 0xaa}, {0x00, 0xc9, 0x60, 0xaa},
+ {0x00, 0x41, 0x38, 0xaa}, {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x02, 0xcc}, {0xb6, 0x02, 0x80, 0xcc},
+ {0xb6, 0x05, 0x01, 0xcc}, {0xb6, 0x04, 0xe0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x13, 0xcc},
+ {0xb6, 0x18, 0x02, 0xcc}, {0xb6, 0x17, 0x58, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x45, 0xcc},
+ {0x00, 0x77, 0x05, 0xaa},
+ {},
+};
+
+static const __u8 ov7670_initQVGA_JPG[][4] = {
+ {0xb3, 0x01, 0x05, 0xcc}, {0x00, 0x00, 0x30, 0xdd},
+ {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x10, 0xdd},
+ {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x10, 0xdd},
+ {0xb3, 0x00, 0x66, 0xcc}, {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc}, {0xb3, 0x03, 0x1f, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc}, {0x00, 0x12, 0x80, 0xaa},
+ {0x00, 0x00, 0x20, 0xdd}, {0x00, 0x12, 0x00, 0xaa},
+ {0x00, 0x11, 0x40, 0xaa}, {0x00, 0x6b, 0x0a, 0xaa},
+ {0x00, 0x3a, 0x04, 0xaa}, {0x00, 0x40, 0xc0, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa}, {0x00, 0x7a, 0x29, 0xaa},
+ {0x00, 0x7b, 0x0e, 0xaa}, {0x00, 0x7c, 0x1a, 0xaa},
+ {0x00, 0x7d, 0x31, 0xaa}, {0x00, 0x7e, 0x53, 0xaa},
+ {0x00, 0x7f, 0x60, 0xaa}, {0x00, 0x80, 0x6b, 0xaa},
+ {0x00, 0x81, 0x73, 0xaa}, {0x00, 0x82, 0x7b, 0xaa},
+ {0x00, 0x83, 0x82, 0xaa}, {0x00, 0x84, 0x89, 0xaa},
+ {0x00, 0x85, 0x96, 0xaa}, {0x00, 0x86, 0xa1, 0xaa},
+ {0x00, 0x87, 0xb7, 0xaa}, {0x00, 0x88, 0xcc, 0xaa},
+ {0x00, 0x89, 0xe1, 0xaa}, {0x00, 0x13, 0xe0, 0xaa},
+ {0x00, 0x00, 0x00, 0xaa}, {0x00, 0x10, 0x00, 0xaa},
+ {0x00, 0x0d, 0x40, 0xaa}, {0x00, 0x14, 0x28, 0xaa},
+ {0x00, 0xa5, 0x05, 0xaa}, {0x00, 0xab, 0x07, 0xaa},
+ {0x00, 0x24, 0x95, 0xaa}, {0x00, 0x25, 0x33, 0xaa},
+ {0x00, 0x26, 0xe3, 0xaa}, {0x00, 0x9f, 0x88, 0xaa},
+ {0x00, 0xa0, 0x78, 0xaa}, {0x00, 0x55, 0x90, 0xaa},
+ {0x00, 0xa1, 0x03, 0xaa}, {0x00, 0xa6, 0xe0, 0xaa},
+ {0x00, 0xa7, 0xd8, 0xaa}, {0x00, 0xa8, 0xf0, 0xaa},
+ {0x00, 0xa9, 0x90, 0xaa}, {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x13, 0xe5, 0xaa}, {0x00, 0x0e, 0x61, 0xaa},
+ {0x00, 0x0f, 0x4b, 0xaa}, {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x1e, 0x07, 0xaa}, {0x00, 0x21, 0x02, 0xaa},
+ {0x00, 0x22, 0x91, 0xaa}, {0x00, 0x29, 0x07, 0xaa},
+ {0x00, 0x33, 0x0b, 0xaa}, {0x00, 0x35, 0x0b, 0xaa},
+ {0x00, 0x37, 0x1d, 0xaa}, {0x00, 0x38, 0x71, 0xaa},
+ {0x00, 0x39, 0x2a, 0xaa}, {0x00, 0x3c, 0x78, 0xaa},
+ {0x00, 0x4d, 0x40, 0xaa}, {0x00, 0x4e, 0x20, 0xaa},
+ {0x00, 0x74, 0x19, 0xaa}, {0x00, 0x8d, 0x4f, 0xaa},
+ {0x00, 0x8e, 0x00, 0xaa}, {0x00, 0x8f, 0x00, 0xaa},
+ {0x00, 0x90, 0x00, 0xaa}, {0x00, 0x91, 0x00, 0xaa},
+ {0x00, 0x96, 0x00, 0xaa}, {0x00, 0x9a, 0x80, 0xaa},
+ {0x00, 0xb0, 0x84, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa},
+ {0x00, 0xb2, 0x0e, 0xaa}, {0x00, 0xb3, 0x82, 0xaa},
+ {0x00, 0xb8, 0x0a, 0xaa}, {0x00, 0x43, 0x14, 0xaa},
+ {0x00, 0x44, 0xf0, 0xaa}, {0x00, 0x45, 0x45, 0xaa},
+ {0x00, 0x46, 0x63, 0xaa}, {0x00, 0x47, 0x2d, 0xaa},
+ {0x00, 0x48, 0x46, 0xaa}, {0x00, 0x59, 0x88, 0xaa},
+ {0x00, 0x5a, 0xa0, 0xaa}, {0x00, 0x5b, 0xc6, 0xaa},
+ {0x00, 0x5c, 0x7d, 0xaa}, {0x00, 0x5d, 0x5f, 0xaa},
+ {0x00, 0x5e, 0x19, 0xaa}, {0x00, 0x6c, 0x0a, 0xaa},
+ {0x00, 0x6d, 0x55, 0xaa}, {0x00, 0x6e, 0x11, 0xaa},
+ {0x00, 0x6f, 0x9e, 0xaa}, {0x00, 0x69, 0x00, 0xaa},
+ {0x00, 0x6a, 0x40, 0xaa}, {0x00, 0x01, 0x40, 0xaa},
+ {0x00, 0x02, 0x40, 0xaa}, {0x00, 0x13, 0xe7, 0xaa},
+ {0x00, 0x5f, 0xf0, 0xaa}, {0x00, 0x60, 0xf0, 0xaa},
+ {0x00, 0x61, 0xf0, 0xaa}, {0x00, 0x27, 0xa0, 0xaa},
+ {0x00, 0x28, 0x80, 0xaa}, {0x00, 0x2c, 0x90, 0xaa},
+ {0x00, 0x4f, 0x66, 0xaa}, {0x00, 0x50, 0x66, 0xaa},
+ {0x00, 0x51, 0x00, 0xaa}, {0x00, 0x52, 0x22, 0xaa},
+ {0x00, 0x53, 0x5e, 0xaa}, {0x00, 0x54, 0x80, 0xaa},
+ {0x00, 0x58, 0x9e, 0xaa}, {0x00, 0x41, 0x08, 0xaa},
+ {0x00, 0x3f, 0x00, 0xaa}, {0x00, 0x75, 0x85, 0xaa},
+ {0x00, 0x76, 0xe1, 0xaa}, {0x00, 0x4c, 0x00, 0xaa},
+ {0x00, 0x77, 0x0a, 0xaa}, {0x00, 0x3d, 0x88, 0xaa},
+ {0x00, 0x4b, 0x09, 0xaa}, {0x00, 0xc9, 0x60, 0xaa},
+ {0x00, 0x41, 0x38, 0xaa}, {0x00, 0x62, 0x30, 0xaa},
+ {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x64, 0x08, 0xaa},
+ {0x00, 0x94, 0x07, 0xaa}, {0x00, 0x95, 0x0b, 0xaa},
+ {0x00, 0x65, 0x00, 0xaa}, {0x00, 0x66, 0x05, 0xaa},
+ {0x00, 0x56, 0x50, 0xaa}, {0x00, 0x34, 0x11, 0xaa},
+ {0x00, 0xa4, 0x88, 0xaa}, {0x00, 0x96, 0x00, 0xaa},
+ {0x00, 0x97, 0x30, 0xaa}, {0x00, 0x98, 0x20, 0xaa},
+ {0x00, 0x99, 0x30, 0xaa}, {0x00, 0x9a, 0x84, 0xaa},
+ {0x00, 0x9b, 0x29, 0xaa}, {0x00, 0x9c, 0x03, 0xaa},
+ {0x00, 0x78, 0x04, 0xaa}, {0x00, 0x79, 0x01, 0xaa},
+ {0x00, 0xc8, 0xf0, 0xaa}, {0x00, 0x79, 0x0f, 0xaa},
+ {0x00, 0xc8, 0x00, 0xaa}, {0x00, 0x79, 0x10, 0xaa},
+ {0x00, 0xc8, 0x7e, 0xaa}, {0x00, 0x79, 0x0a, 0xaa},
+ {0x00, 0xc8, 0x80, 0xaa}, {0x00, 0x79, 0x0b, 0xaa},
+ {0x00, 0xc8, 0x01, 0xaa}, {0x00, 0x79, 0x0c, 0xaa},
+ {0x00, 0xc8, 0x0f, 0xaa}, {0x00, 0x79, 0x0d, 0xaa},
+ {0x00, 0xc8, 0x20, 0xaa}, {0x00, 0x79, 0x09, 0xaa},
+ {0x00, 0xc8, 0x80, 0xaa}, {0x00, 0x79, 0x02, 0xaa},
+ {0x00, 0xc8, 0xc0, 0xaa}, {0x00, 0x79, 0x03, 0xaa},
+ {0x00, 0xc8, 0x40, 0xaa}, {0x00, 0x79, 0x05, 0xaa},
+ {0x00, 0xc8, 0x30, 0xaa}, {0x00, 0x79, 0x26, 0xaa},
+ {0x00, 0x11, 0x40, 0xaa}, {0x00, 0x3a, 0x04, 0xaa},
+ {0x00, 0x12, 0x00, 0xaa}, {0x00, 0x40, 0xc0, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa}, {0x00, 0x17, 0x14, 0xaa},
+ {0x00, 0x18, 0x02, 0xaa}, {0x00, 0x32, 0x92, 0xaa},
+ {0x00, 0x19, 0x02, 0xaa}, {0x00, 0x1a, 0x7a, 0xaa},
+ {0x00, 0x03, 0x0a, 0xaa}, {0x00, 0x0c, 0x00, 0xaa},
+ {0x00, 0x3e, 0x00, 0xaa}, {0x00, 0x70, 0x3a, 0xaa},
+ {0x00, 0x71, 0x35, 0xaa}, {0x00, 0x72, 0x11, 0xaa},
+ {0x00, 0x73, 0xf0, 0xaa}, {0x00, 0xa2, 0x02, 0xaa},
+ {0x00, 0xb1, 0x00, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa},
+ {0x00, 0x1e, 0x37, 0xaa}, {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x24, 0x80, 0xaa}, {0x00, 0x25, 0x74, 0xaa},
+ {0x00, 0x26, 0xd3, 0xaa}, {0x00, 0x0d, 0x00, 0xaa},
+ {0x00, 0x14, 0x18, 0xaa}, {0x00, 0x9d, 0x99, 0xaa},
+ {0x00, 0x9e, 0x7f, 0xaa}, {0x00, 0x64, 0x08, 0xaa},
+ {0x00, 0x94, 0x07, 0xaa}, {0x00, 0x95, 0x06, 0xaa},
+ {0x00, 0x66, 0x05, 0xaa}, {0x00, 0x41, 0x08, 0xaa},
+ {0x00, 0x3f, 0x00, 0xaa}, {0x00, 0x75, 0x07, 0xaa},
+ {0x00, 0x76, 0xe1, 0xaa}, {0x00, 0x4c, 0x00, 0xaa},
+ {0x00, 0x77, 0x00, 0xaa}, {0x00, 0x3d, 0xc2, 0xaa},
+ {0x00, 0x4b, 0x09, 0xaa}, {0x00, 0xc9, 0x60, 0xaa},
+ {0x00, 0x41, 0x38, 0xaa}, {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc},
+ {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x21, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x45, 0xcc},
+ {0x00, 0x77, 0x05, 0xaa },
+ {},
+};
+
+struct sensor_info {
+ int sensorId;
+ __u8 I2cAdd;
+ __u8 IdAdd;
+ __u16 VpId;
+ __u8 m1;
+ __u8 m2;
+ __u8 op;
+ };
+
+static const struct sensor_info sensor_info_data[] = {
+/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */
+ {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+ {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
+ {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01},
+ {SENSOR_MI1320, 0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01},
+ {SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
+ {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+};
+
+/* read 'len' bytes in gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+ __u16 req,
+ __u16 index,
+ __u16 len)
+{
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 1, /* value */
+ index, gspca_dev->usb_buf, len,
+ 500);
+}
+
+static void reg_w(struct usb_device *dev,
+ __u16 req,
+ __u16 value,
+ __u16 index)
+{
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0,
+ 500);
+}
+
+static void read_sensor_register(struct gspca_dev *gspca_dev,
+ __u16 address, __u16 *value)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 ldata, mdata, hdata;
+ int retry = 50;
+
+ *value = 0;
+
+ reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+ /*PDEBUG(D_PROBE, " I2c Bus Busy Wait 0x%02X ", tmpvalue); */
+ if (!(gspca_dev->usb_buf[0] & 0x02)) {
+ PDEBUG(D_ERR, "I2c Bus Busy Wait %d",
+ gspca_dev->usb_buf[0] & 0x02);
+ return;
+ }
+ reg_w(dev, 0xa0, address, 0xb33a);
+ reg_w(dev, 0xa0, 0x02, 0xb339);
+
+ reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+ while (retry-- && gspca_dev->usb_buf[0]) {
+ reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+/* PDEBUG(D_PROBE, "Read again 0xb33b %d", tmpvalue); */
+ msleep(1);
+ }
+ reg_r(gspca_dev, 0xa1, 0xb33e, 1);
+ hdata = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0xa1, 0xb33d, 1);
+ mdata = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0xa1, 0xb33c, 1);
+ ldata = gspca_dev->usb_buf[0];
+ PDEBUG(D_PROBE, "Read Sensor h (0x%02X) m (0x%02X) l (0x%02X)",
+ hdata, mdata, ldata);
+ reg_r(gspca_dev, 0xa1, 0xb334, 1);
+ if (gspca_dev->usb_buf[0] == 0x02)
+ *value = (ldata << 8) + mdata;
+ else
+ *value = ldata;
+}
+
+static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int i;
+ __u16 value;
+ const struct sensor_info *ptsensor_info;
+
+ reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
+ PDEBUG(D_PROBE, "check sensor header %d", gspca_dev->usb_buf[0]);
+ for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) {
+ ptsensor_info = &sensor_info_data[i];
+ reg_w(dev, 0xa0, 0x02, 0xb334);
+ reg_w(dev, 0xa0, ptsensor_info->m1, 0xb300);
+ reg_w(dev, 0xa0, ptsensor_info->m2, 0xb300);
+ reg_w(dev, 0xa0, 0x01, 0xb308);
+ reg_w(dev, 0xa0, 0x0c, 0xb309);
+ reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
+/* PDEBUG(D_PROBE,
+ "check sensor VC032X -> %d Add -> ox%02X!",
+ i, ptsensor_info->I2cAdd); */
+ reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
+ read_sensor_register(gspca_dev, ptsensor_info->IdAdd, &value);
+ if (value == ptsensor_info->VpId) {
+/* PDEBUG(D_PROBE, "find sensor VC032X -> ox%04X!",
+ ptsensor_info->VpId); */
+ return ptsensor_info->sensorId;
+ }
+ }
+ return -1;
+}
+
+static __u8 i2c_write(struct gspca_dev *gspca_dev,
+ __u8 reg, const __u8 *val, __u8 size)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ if (size > 3 || size < 1)
+ return -EINVAL;
+ reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+ reg_w(dev, 0xa0, size, 0xb334);
+ reg_w(dev, 0xa0, reg, 0xb33a);
+ switch (size) {
+ case 1:
+ reg_w(dev, 0xa0, val[0], 0xb336);
+ break;
+ case 2:
+ reg_w(dev, 0xa0, val[0], 0xb336);
+ reg_w(dev, 0xa0, val[1], 0xb337);
+ break;
+ case 3:
+ reg_w(dev, 0xa0, val[0], 0xb336);
+ reg_w(dev, 0xa0, val[1], 0xb337);
+ reg_w(dev, 0xa0, val[2], 0xb338);
+ break;
+ default:
+ reg_w(dev, 0xa0, 0x01, 0xb334);
+ return -EINVAL;
+ }
+ reg_w(dev, 0xa0, 0x01, 0xb339);
+ reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+ return gspca_dev->usb_buf[0] == 0;
+}
+
+static void put_tab_to_reg(struct gspca_dev *gspca_dev,
+ const __u8 *tab, __u8 tabsize, __u16 addr)
+{
+ int j;
+ __u16 ad = addr;
+
+ for (j = 0; j < tabsize; j++)
+ reg_w(gspca_dev->dev, 0xa0, tab[j], ad++);
+}
+
+static void usb_exchange(struct gspca_dev *gspca_dev,
+ const __u8 data[][4])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int i = 0;
+
+ for (;;) {
+ switch (data[i][3]) {
+ default:
+ return;
+ case 0xcc: /* normal write */
+ reg_w(dev, 0xa0, data[i][2],
+ ((data[i][0])<<8) | data[i][1]);
+ break;
+ case 0xaa: /* i2c op */
+ i2c_write(gspca_dev, data[i][1], &data[i][2], 1);
+ break;
+ case 0xbb: /* i2c op */
+ i2c_write(gspca_dev, data[i][0], &data[i][1], 2);
+ break;
+ case 0xdd:
+ msleep(data[i][2] + 10);
+ break;
+ }
+ i++;
+ }
+ /*not reached*/
+}
+
+/*
+ "GammaT"=hex:04,17,31,4f,6a,83,99,ad,bf,ce,da,e5,ee,f5,fb,ff,ff
+ "MatrixT"=hex:60,f9,e5,e7,50,05,f3,e6,66
+ */
+
+static void vc0321_reset(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb04d);
+ reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb301);
+ msleep(100);
+ reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb003);
+ msleep(100);
+}
+
+/* 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 usb_device *dev = gspca_dev->dev;
+ struct cam *cam;
+ int sensor;
+ __u16 product;
+
+ product = id->idProduct;
+ sd->bridge = BRIDGE_VC0321;
+ switch (id->idVendor) {
+ case 0x0ac8: /* Vimicro z-star */
+ switch (product) {
+ case 0x0323:
+ sd->bridge = BRIDGE_VC0323;
+ break;
+ }
+ break;
+ case 0x17ef: /* Lenovo */
+/* switch (product) { */
+/* case 0x4802: * Lenovo MI1310_SOC */
+ sd->bridge = BRIDGE_VC0323;
+/* break; */
+/* } */
+ break;
+ }
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x02;
+ if (sd->bridge == BRIDGE_VC0321) {
+ cam->cam_mode = vc0321_mode;
+ cam->nmodes = ARRAY_SIZE(vc0321_mode);
+ } else {
+ cam->cam_mode = vc0323_mode;
+ cam->nmodes = ARRAY_SIZE(vc0323_mode);
+ }
+
+ vc0321_reset(gspca_dev);
+ sensor = vc032x_probe_sensor(gspca_dev);
+ switch (sensor) {
+ case -1:
+ PDEBUG(D_PROBE, "Unknown sensor...");
+ return -EINVAL;
+ case SENSOR_HV7131R:
+ PDEBUG(D_PROBE, "Find Sensor HV7131R");
+ sd->sensor = SENSOR_HV7131R;
+ break;
+ case SENSOR_MI1310_SOC:
+ PDEBUG(D_PROBE, "Find Sensor MI1310_SOC");
+ sd->sensor = SENSOR_MI1310_SOC;
+ break;
+ case SENSOR_MI1320:
+ PDEBUG(D_PROBE, "Find Sensor MI1320");
+ sd->sensor = SENSOR_MI1320;
+ break;
+ case SENSOR_OV7660:
+ PDEBUG(D_PROBE, "Find Sensor OV7660");
+ sd->sensor = SENSOR_OV7660;
+ break;
+ case SENSOR_OV7670:
+ PDEBUG(D_PROBE, "Find Sensor OV7670");
+ sd->sensor = SENSOR_OV7670;
+ break;
+ case SENSOR_PO3130NC:
+ PDEBUG(D_PROBE, "Find Sensor PO3130NC");
+ sd->sensor = SENSOR_PO3130NC;
+ break;
+ }
+
+ sd->qindex = 7;
+ sd->autogain = AUTOGAIN_DEF;
+ sd->lightfreq = FREQ_DEF;
+
+ if (sd->bridge == BRIDGE_VC0321) {
+ reg_r(gspca_dev, 0x8a, 0, 3);
+ reg_w(dev, 0x87, 0x00, 0x0f0f);
+
+ reg_r(gspca_dev, 0x8b, 0, 3);
+ reg_w(dev, 0x88, 0x00, 0x0202);
+ }
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+static void setquality(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setlightfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ static const __u8 (*ov7660_freq_tb[3])[4] =
+ {ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ};
+
+ if (sd->sensor != SENSOR_OV7660)
+ return;
+ usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]);
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ const __u8 *GammaT = NULL;
+ const __u8 *MatrixT = NULL;
+ int mode;
+
+ /* Assume start use the good resolution from gspca_dev->mode */
+ if (sd->bridge == BRIDGE_VC0321) {
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
+ }
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ GammaT = hv7131r_gamma;
+ MatrixT = hv7131r_matrix;
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, hv7131r_initQVGA_data);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, hv7131r_initVGA_data);
+ }
+ break;
+ case SENSOR_OV7660:
+ GammaT = ov7660_gamma;
+ MatrixT = ov7660_matrix;
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, ov7660_initQVGA_data);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, ov7660_initVGA_data);
+ }
+ break;
+ case SENSOR_OV7670:
+ /*GammaT = ov7660_gamma; */
+ /*MatrixT = ov7660_matrix; */
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, ov7670_initQVGA_JPG);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, ov7670_initVGA_JPG);
+ }
+ break;
+ case SENSOR_MI1310_SOC:
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, mi1310_socinitQVGA_JPG);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, mi1310_socinitVGA_JPG);
+ }
+ break;
+ case SENSOR_MI1320:
+ GammaT = mi1320_gamma;
+ MatrixT = mi1320_matrix;
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, mi1320_initQVGA_data);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, mi1320_initVGA_data);
+ }
+ break;
+ case SENSOR_PO3130NC:
+ GammaT = po3130_gamma;
+ MatrixT = po3130_matrix;
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, po3130_initQVGA_data);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, po3130_initVGA_data);
+ }
+ usb_exchange(gspca_dev, po3130_rundata);
+ break;
+ default:
+ PDEBUG(D_PROBE, "Damned !! no sensor found Bye");
+ return;
+ }
+ if (GammaT && MatrixT) {
+ put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a);
+ put_tab_to_reg(gspca_dev, GammaT, 17, 0xb85b);
+ put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c);
+ put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
+
+ /* Seem SHARPNESS */
+ /*
+ reg_w(gspca_dev->dev, 0xa0, 0x80, 0xb80a);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80b);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80e);
+ */
+ /* all 0x40 ??? do nothing
+ reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb822);
+ reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb823);
+ reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb824);
+ */
+ /* Only works for HV7131R ??
+ reg_r (gspca_dev, 0xa1, 0xb881, 1);
+ reg_w(gspca_dev->dev, 0xa0, 0xfe01, 0xb881);
+ reg_w(gspca_dev->dev, 0xa0, 0x79, 0xb801);
+ */
+ /* only hv7131r et ov7660
+ reg_w(gspca_dev->dev, 0xa0, 0x20, 0xb827);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb826); * ISP_GAIN 80
+ reg_w(gspca_dev->dev, 0xa0, 0x23, 0xb800); * ISP CTRL_BAS
+ */
+ /* set the led on 0x0892 0x0896 */
+ reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+ msleep(100);
+ setquality(gspca_dev);
+ setautogain(gspca_dev);
+ setlightfreq(gspca_dev);
+ }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ reg_w(dev, 0x89, 0xffff, 0xffff);
+ reg_w(dev, 0xa0, 0x01, 0xb301);
+ reg_w(dev, 0xa0, 0x09, 0xb003);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ reg_w(dev, 0x89, 0xffff, 0xffff);
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+/* struct usb_device *dev = gspca_dev->dev;
+ __u8 buffread;
+
+ reg_w(dev, 0x89, 0xffff, 0xffff);
+ reg_w(dev, 0xa0, 0x01, 0xb301);
+ reg_w(dev, 0xa0, 0x09, 0xb303);
+ reg_w(dev, 0x89, 0xffff, 0xffff);
+*/
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso pkt length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (data[0] == 0xff && data[1] == 0xd8) {
+ PDEBUG(D_PACK,
+ "vc032x header packet found len %d", len);
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+ if (sd->bridge == BRIDGE_VC0321) {
+#define VCHDRSZ 46
+ data += VCHDRSZ;
+ len -= VCHDRSZ;
+#undef VCHDRSZ
+ }
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, len);
+ return;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (gspca_dev->streaming)
+ setautogain(gspca_dev);
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->lightfreq = val;
+ if (gspca_dev->streaming)
+ setlightfreq(gspca_dev);
+ return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->lightfreq;
+ return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+ strcpy((char *) menu->name, "NoFliker");
+ return 0;
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x046d, 0x0892), DVNM("Logitech Orbicam")},
+ {USB_DEVICE(0x046d, 0x0896), DVNM("Logitech Orbicam")},
+ {USB_DEVICE(0x0ac8, 0x0321), DVNM("Vimicro generic vc0321")},
+ {USB_DEVICE(0x0ac8, 0x0323), DVNM("Vimicro Vc0323")},
+ {USB_DEVICE(0x0ac8, 0x0328), DVNM("A4Tech PK-130MG")},
+ {USB_DEVICE(0x0ac8, 0xc001), DVNM("Sony embedded vimicro")},
+ {USB_DEVICE(0x0ac8, 0xc002), DVNM("Sony embedded vimicro")},
+ {USB_DEVICE(0x17ef, 0x4802), DVNM("Lenovo Vc0323+MI1310_SOC")},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/zc3xx-reg.h b/drivers/media/video/gspca/zc3xx-reg.h
new file mode 100644
index 00000000000..f52e09c2cc1
--- /dev/null
+++ b/drivers/media/video/gspca/zc3xx-reg.h
@@ -0,0 +1,261 @@
+/*
+ * zc030x registers
+ *
+ * Copyright (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * The register aliases used here came from this driver:
+ * http://zc0302.sourceforge.net/zc0302.php
+ *
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+/* Define the register map */
+#define ZC3XX_R000_SYSTEMCONTROL 0x0000
+#define ZC3XX_R001_SYSTEMOPERATING 0x0001
+
+/* Picture size */
+#define ZC3XX_R002_CLOCKSELECT 0x0002
+#define ZC3XX_R003_FRAMEWIDTHHIGH 0x0003
+#define ZC3XX_R004_FRAMEWIDTHLOW 0x0004
+#define ZC3XX_R005_FRAMEHEIGHTHIGH 0x0005
+#define ZC3XX_R006_FRAMEHEIGHTLOW 0x0006
+
+/* JPEG control */
+#define ZC3XX_R008_CLOCKSETTING 0x0008
+
+/* Test mode */
+#define ZC3XX_R00B_TESTMODECONTROL 0x000b
+
+/* Frame retreiving */
+#define ZC3XX_R00C_LASTACQTIME 0x000c
+#define ZC3XX_R00D_MONITORRES 0x000d
+#define ZC3XX_R00E_TIMESTAMPHIGH 0x000e
+#define ZC3XX_R00F_TIMESTAMPLOW 0x000f
+#define ZC3XX_R018_FRAMELOST 0x0018
+#define ZC3XX_R019_AUTOADJUSTFPS 0x0019
+#define ZC3XX_R01A_LASTFRAMESTATE 0x001a
+#define ZC3XX_R025_DATACOUNTER 0x0025
+
+/* Stream and sensor specific */
+#define ZC3XX_R010_CMOSSENSORSELECT 0x0010
+#define ZC3XX_R011_VIDEOSTATUS 0x0011
+#define ZC3XX_R012_VIDEOCONTROLFUNC 0x0012
+
+/* Horizontal and vertical synchros */
+#define ZC3XX_R01D_HSYNC_0 0x001d
+#define ZC3XX_R01E_HSYNC_1 0x001e
+#define ZC3XX_R01F_HSYNC_2 0x001f
+#define ZC3XX_R020_HSYNC_3 0x0020
+
+/* Target picture size in byte */
+#define ZC3XX_R022_TARGETPICTSIZE_0 0x0022
+#define ZC3XX_R023_TARGETPICTSIZE_1 0x0023
+#define ZC3XX_R024_TARGETPICTSIZE_2 0x0024
+
+/* Audio registers */
+#define ZC3XX_R030_AUDIOADC 0x0030
+#define ZC3XX_R031_AUDIOSTREAMSTATUS 0x0031
+#define ZC3XX_R032_AUDIOSTATUS 0x0032
+
+/* Sensor interface */
+#define ZC3XX_R080_HBLANKHIGH 0x0080
+#define ZC3XX_R081_HBLANKLOW 0x0081
+#define ZC3XX_R082_RESETLEVELADDR 0x0082
+#define ZC3XX_R083_RGAINADDR 0x0083
+#define ZC3XX_R084_GGAINADDR 0x0084
+#define ZC3XX_R085_BGAINADDR 0x0085
+#define ZC3XX_R086_EXPTIMEHIGH 0x0086
+#define ZC3XX_R087_EXPTIMEMID 0x0087
+#define ZC3XX_R088_EXPTIMELOW 0x0088
+#define ZC3XX_R089_RESETBLACKHIGH 0x0089
+#define ZC3XX_R08A_RESETWHITEHIGH 0x008a
+#define ZC3XX_R08B_I2CDEVICEADDR 0x008b
+#define ZC3XX_R08C_I2CIDLEANDNACK 0x008c
+#define ZC3XX_R08D_COMPABILITYMODE 0x008d
+#define ZC3XX_R08E_COMPABILITYMODE2 0x008e
+
+/* I2C control */
+#define ZC3XX_R090_I2CCOMMAND 0x0090
+#define ZC3XX_R091_I2CSTATUS 0x0091
+#define ZC3XX_R092_I2CADDRESSSELECT 0x0092
+#define ZC3XX_R093_I2CSETVALUE 0x0093
+#define ZC3XX_R094_I2CWRITEACK 0x0094
+#define ZC3XX_R095_I2CREAD 0x0095
+#define ZC3XX_R096_I2CREADACK 0x0096
+
+/* Window inside the sensor array */
+#define ZC3XX_R097_WINYSTARTHIGH 0x0097
+#define ZC3XX_R098_WINYSTARTLOW 0x0098
+#define ZC3XX_R099_WINXSTARTHIGH 0x0099
+#define ZC3XX_R09A_WINXSTARTLOW 0x009a
+#define ZC3XX_R09B_WINHEIGHTHIGH 0x009b
+#define ZC3XX_R09C_WINHEIGHTLOW 0x009c
+#define ZC3XX_R09D_WINWIDTHHIGH 0x009d
+#define ZC3XX_R09E_WINWIDTHLOW 0x009e
+#define ZC3XX_R119_FIRSTYHIGH 0x0119
+#define ZC3XX_R11A_FIRSTYLOW 0x011a
+#define ZC3XX_R11B_FIRSTXHIGH 0x011b
+#define ZC3XX_R11C_FIRSTXLOW 0x011c
+
+/* Max sensor array size */
+#define ZC3XX_R09F_MAXXHIGH 0x009f
+#define ZC3XX_R0A0_MAXXLOW 0x00a0
+#define ZC3XX_R0A1_MAXYHIGH 0x00a1
+#define ZC3XX_R0A2_MAXYLOW 0x00a2
+#define ZC3XX_R0A3_EXPOSURETIMEHIGH 0x00a3
+#define ZC3XX_R0A4_EXPOSURETIMELOW 0x00a4
+#define ZC3XX_R0A5_EXPOSUREGAIN 0x00a5
+#define ZC3XX_R0A6_EXPOSUREBLACKLVL 0x00a6
+
+/* Other registers */
+#define ZC3XX_R100_OPERATIONMODE 0x0100
+#define ZC3XX_R101_SENSORCORRECTION 0x0101
+
+/* Gains */
+#define ZC3XX_R116_RGAIN 0x0116
+#define ZC3XX_R117_GGAIN 0x0117
+#define ZC3XX_R118_BGAIN 0x0118
+#define ZC3XX_R11D_GLOBALGAIN 0x011d
+#define ZC3XX_R1A8_DIGITALGAIN 0x01a8
+#define ZC3XX_R1A9_DIGITALLIMITDIFF 0x01a9
+#define ZC3XX_R1AA_DIGITALGAINSTEP 0x01aa
+
+/* Auto correction */
+#define ZC3XX_R180_AUTOCORRECTENABLE 0x0180
+#define ZC3XX_R181_WINXSTART 0x0181
+#define ZC3XX_R182_WINXWIDTH 0x0182
+#define ZC3XX_R183_WINXCENTER 0x0183
+#define ZC3XX_R184_WINYSTART 0x0184
+#define ZC3XX_R185_WINYWIDTH 0x0185
+#define ZC3XX_R186_WINYCENTER 0x0186
+
+/* Gain range */
+#define ZC3XX_R187_MAXGAIN 0x0187
+#define ZC3XX_R188_MINGAIN 0x0188
+
+/* Auto exposure and white balance */
+#define ZC3XX_R189_AWBSTATUS 0x0189
+#define ZC3XX_R18A_AWBFREEZE 0x018a
+#define ZC3XX_R18B_AESTATUS 0x018b
+#define ZC3XX_R18C_AEFREEZE 0x018c
+#define ZC3XX_R18F_AEUNFREEZE 0x018f
+#define ZC3XX_R190_EXPOSURELIMITHIGH 0x0190
+#define ZC3XX_R191_EXPOSURELIMITMID 0x0191
+#define ZC3XX_R192_EXPOSURELIMITLOW 0x0192
+#define ZC3XX_R195_ANTIFLICKERHIGH 0x0195
+#define ZC3XX_R196_ANTIFLICKERMID 0x0196
+#define ZC3XX_R197_ANTIFLICKERLOW 0x0197
+
+/* What is this ? */
+#define ZC3XX_R18D_YTARGET 0x018d
+#define ZC3XX_R18E_RESETLVL 0x018e
+
+/* Color */
+#define ZC3XX_R1A0_REDMEANAFTERAGC 0x01a0
+#define ZC3XX_R1A1_GREENMEANAFTERAGC 0x01a1
+#define ZC3XX_R1A2_BLUEMEANAFTERAGC 0x01a2
+#define ZC3XX_R1A3_REDMEANAFTERAWB 0x01a3
+#define ZC3XX_R1A4_GREENMEANAFTERAWB 0x01a4
+#define ZC3XX_R1A5_BLUEMEANAFTERAWB 0x01a5
+#define ZC3XX_R1A6_YMEANAFTERAE 0x01a6
+#define ZC3XX_R1A7_CALCGLOBALMEAN 0x01a7
+
+#define ZC3XX_R1A2_BLUEMEANAFTERAGC 0x01a2
+
+/* Matrixes */
+
+/* Color matrix is like :
+ R' = R * RGB00 + G * RGB01 + B * RGB02 + RGB03
+ G' = R * RGB10 + G * RGB11 + B * RGB22 + RGB13
+ B' = R * RGB20 + G * RGB21 + B * RGB12 + RGB23
+ */
+#define ZC3XX_R10A_RGB00 0x010a
+#define ZC3XX_R10B_RGB01 0x010b
+#define ZC3XX_R10C_RGB02 0x010c
+#define ZC3XX_R113_RGB03 0x0113
+#define ZC3XX_R10D_RGB10 0x010d
+#define ZC3XX_R10E_RGB11 0x010e
+#define ZC3XX_R10F_RGB12 0x010f
+#define ZC3XX_R114_RGB13 0x0114
+#define ZC3XX_R110_RGB20 0x0110
+#define ZC3XX_R111_RGB21 0x0111
+#define ZC3XX_R112_RGB22 0x0112
+#define ZC3XX_R115_RGB23 0x0115
+
+/* Gamma matrix */
+#define ZC3XX_R120_GAMMA00 0x0120
+#define ZC3XX_R121_GAMMA01 0x0121
+#define ZC3XX_R122_GAMMA02 0x0122
+#define ZC3XX_R123_GAMMA03 0x0123
+#define ZC3XX_R124_GAMMA04 0x0124
+#define ZC3XX_R125_GAMMA05 0x0125
+#define ZC3XX_R126_GAMMA06 0x0126
+#define ZC3XX_R127_GAMMA07 0x0127
+#define ZC3XX_R128_GAMMA08 0x0128
+#define ZC3XX_R129_GAMMA09 0x0129
+#define ZC3XX_R12A_GAMMA0A 0x012a
+#define ZC3XX_R12B_GAMMA0B 0x012b
+#define ZC3XX_R12C_GAMMA0C 0x012c
+#define ZC3XX_R12D_GAMMA0D 0x012d
+#define ZC3XX_R12E_GAMMA0E 0x012e
+#define ZC3XX_R12F_GAMMA0F 0x012f
+#define ZC3XX_R130_GAMMA10 0x0130
+#define ZC3XX_R131_GAMMA11 0x0131
+#define ZC3XX_R132_GAMMA12 0x0132
+#define ZC3XX_R133_GAMMA13 0x0133
+#define ZC3XX_R134_GAMMA14 0x0134
+#define ZC3XX_R135_GAMMA15 0x0135
+#define ZC3XX_R136_GAMMA16 0x0136
+#define ZC3XX_R137_GAMMA17 0x0137
+#define ZC3XX_R138_GAMMA18 0x0138
+#define ZC3XX_R139_GAMMA19 0x0139
+#define ZC3XX_R13A_GAMMA1A 0x013a
+#define ZC3XX_R13B_GAMMA1B 0x013b
+#define ZC3XX_R13C_GAMMA1C 0x013c
+#define ZC3XX_R13D_GAMMA1D 0x013d
+#define ZC3XX_R13E_GAMMA1E 0x013e
+#define ZC3XX_R13F_GAMMA1F 0x013f
+
+/* Luminance gamma */
+#define ZC3XX_R140_YGAMMA00 0x0140
+#define ZC3XX_R141_YGAMMA01 0x0141
+#define ZC3XX_R142_YGAMMA02 0x0142
+#define ZC3XX_R143_YGAMMA03 0x0143
+#define ZC3XX_R144_YGAMMA04 0x0144
+#define ZC3XX_R145_YGAMMA05 0x0145
+#define ZC3XX_R146_YGAMMA06 0x0146
+#define ZC3XX_R147_YGAMMA07 0x0147
+#define ZC3XX_R148_YGAMMA08 0x0148
+#define ZC3XX_R149_YGAMMA09 0x0149
+#define ZC3XX_R14A_YGAMMA0A 0x014a
+#define ZC3XX_R14B_YGAMMA0B 0x014b
+#define ZC3XX_R14C_YGAMMA0C 0x014c
+#define ZC3XX_R14D_YGAMMA0D 0x014d
+#define ZC3XX_R14E_YGAMMA0E 0x014e
+#define ZC3XX_R14F_YGAMMA0F 0x014f
+#define ZC3XX_R150_YGAMMA10 0x0150
+#define ZC3XX_R151_YGAMMA11 0x0151
+
+#define ZC3XX_R1C5_SHARPNESSMODE 0x01c5
+#define ZC3XX_R1C6_SHARPNESS00 0x01c6
+#define ZC3XX_R1C7_SHARPNESS01 0x01c7
+#define ZC3XX_R1C8_SHARPNESS02 0x01c8
+#define ZC3XX_R1C9_SHARPNESS03 0x01c9
+#define ZC3XX_R1CA_SHARPNESS04 0x01ca
+#define ZC3XX_R1CB_SHARPNESS05 0x01cb
+
+/* Synchronization */
+#define ZC3XX_R190_SYNC00LOW 0x0190
+#define ZC3XX_R191_SYNC00MID 0x0191
+#define ZC3XX_R192_SYNC00HIGH 0x0192
+#define ZC3XX_R195_SYNC01LOW 0x0195
+#define ZC3XX_R196_SYNC01MID 0x0196
+#define ZC3XX_R197_SYNC01HIGH 0x0197
+
+/* Dead pixels */
+#define ZC3XX_R250_DEADPIXELSMODE 0x0250
+
+/* EEPROM */
+#define ZC3XX_R300_EEPROMCONFIG 0x0300
+#define ZC3XX_R301_EEPROMACCESS 0x0301
+#define ZC3XX_R302_EEPROMSTATUS 0x0302
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
new file mode 100644
index 00000000000..b761b11c5c6
--- /dev/null
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -0,0 +1,7623 @@
+/*
+ * Z-Star/Vimicro zc301/zc302p/vc30x library
+ * Copyright (C) 2004 2005 2006 Michel Xhaard
+ * mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define MODULE_NAME "zc3xx"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>, "
+ "Serge A. Suchkov <Serge.A.S@tochka.ru>");
+MODULE_DESCRIPTION("GSPCA ZC03xx/VC3xx USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+static int force_sensor = -1;
+
+#include "jpeg.h"
+#include "zc3xx-reg.h"
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ __u8 brightness;
+ __u8 contrast;
+ __u8 gamma;
+ __u8 autogain;
+ __u8 lightfreq;
+ __u8 sharpness;
+
+ char qindex;
+ char sensor; /* Type of image sensor chip */
+/* !! values used in different tables */
+#define SENSOR_CS2102 0
+#define SENSOR_CS2102K 1
+#define SENSOR_GC0305 2
+#define SENSOR_HDCS2020 3
+#define SENSOR_HDCS2020b 4
+#define SENSOR_HV7131B 5
+#define SENSOR_HV7131C 6
+#define SENSOR_ICM105A 7
+#define SENSOR_MC501CB 8
+#define SENSOR_OV7620 9
+/*#define SENSOR_OV7648 9 - same values */
+#define SENSOR_OV7630C 10
+#define SENSOR_PAS106 11
+#define SENSOR_PB0330 12
+#define SENSOR_PO2030 13
+#define SENSOR_TAS5130CK 14
+#define SENSOR_TAS5130CXX 15
+#define SENSOR_TAS5130C_VF0250 16
+#define SENSOR_MAX 17
+ unsigned short chip_revision;
+};
+
+/* 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);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 128,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 128,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_GAMMA 2
+ {
+ {
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+ .minimum = 1,
+ .maximum = 6,
+ .step = 1,
+ .default_value = 4,
+ },
+ .set = sd_setgamma,
+ .get = sd_getgamma,
+ },
+#define SD_AUTOGAIN 3
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+#define SD_FREQ 4
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light frequency filter",
+ .minimum = 0,
+ .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq,
+ },
+#define SD_SHARPNESS 5
+ {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sharpness",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 2,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/* usb exchanges */
+struct usb_action {
+ __u8 req;
+ __u8 val;
+ __u16 idx;
+};
+
+static const struct usb_action cs2102_Initial[] = {
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x20, ZC3XX_R080_HBLANKHIGH},
+ {0xa0, 0x21, ZC3XX_R081_HBLANKLOW},
+ {0xa0, 0x30, ZC3XX_R083_RGAINADDR},
+ {0xa0, 0x31, ZC3XX_R084_GGAINADDR},
+ {0xa0, 0x32, ZC3XX_R085_BGAINADDR},
+ {0xa0, 0x23, ZC3XX_R086_EXPTIMEHIGH},
+ {0xa0, 0x24, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x25, ZC3XX_R088_EXPTIMELOW},
+ {0xa0, 0xb3, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xaa, 0x02, 0x0008},
+ {0xaa, 0x03, 0x0000},
+ {0xaa, 0x11, 0x0000},
+ {0xaa, 0x12, 0x0089},
+ {0xaa, 0x13, 0x0000},
+ {0xaa, 0x14, 0x00e9},
+ {0xaa, 0x20, 0x0000},
+ {0xaa, 0x22, 0x0000},
+ {0xaa, 0x0b, 0x0004},
+ {0xaa, 0x30, 0x0030},
+ {0xaa, 0x31, 0x0030},
+ {0xaa, 0x32, 0x0030},
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x10, 0x01ae},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x68, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x00, 0x01ad},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x24, ZC3XX_R120_GAMMA00}, /* gamma 5 */
+ {0xa0, 0x44, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x64, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x84, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x9d, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xb2, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xc4, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xd3, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xe0, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xeb, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xf4, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xfb, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xff, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xff, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x18, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x20, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0e, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x00, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x00, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x01, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf4, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf4, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf4, ZC3XX_R10D_RGB10},
+ {0xa0, 0x58, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf4, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf4, ZC3XX_R110_RGB20},
+ {0xa0, 0xf4, ZC3XX_R111_RGB21},
+ {0xa0, 0x58, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x23, 0x0001},
+ {0xaa, 0x24, 0x0055},
+ {0xaa, 0x25, 0x00cc},
+ {0xaa, 0x21, 0x003f},
+ {0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0xab, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x98, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x30, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0xd4, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x39, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0x70, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xb0, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x40, ZC3XX_R118_BGAIN},
+ {}
+};
+
+static const struct usb_action cs2102_InitialScale[] = {
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x20, ZC3XX_R080_HBLANKHIGH},
+ {0xa0, 0x21, ZC3XX_R081_HBLANKLOW},
+ {0xa0, 0x30, ZC3XX_R083_RGAINADDR},
+ {0xa0, 0x31, ZC3XX_R084_GGAINADDR},
+ {0xa0, 0x32, ZC3XX_R085_BGAINADDR},
+ {0xa0, 0x23, ZC3XX_R086_EXPTIMEHIGH},
+ {0xa0, 0x24, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x25, ZC3XX_R088_EXPTIMELOW},
+ {0xa0, 0xb3, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xaa, 0x02, 0x0008},
+ {0xaa, 0x03, 0x0000},
+ {0xaa, 0x11, 0x0001},
+ {0xaa, 0x12, 0x0087},
+ {0xaa, 0x13, 0x0001},
+ {0xaa, 0x14, 0x00e7},
+ {0xaa, 0x20, 0x0000},
+ {0xaa, 0x22, 0x0000},
+ {0xaa, 0x0b, 0x0004},
+ {0xaa, 0x30, 0x0030},
+ {0xaa, 0x31, 0x0030},
+ {0xaa, 0x32, 0x0030},
+ {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x68, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x00, 0x01ad},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x24, ZC3XX_R120_GAMMA00}, /* gamma 5 */
+ {0xa0, 0x44, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x64, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x84, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x9d, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xb2, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xc4, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xd3, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xe0, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xeb, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xf4, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xfb, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xff, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xff, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x18, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x20, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0e, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x00, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x00, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x01, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf4, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf4, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf4, ZC3XX_R10D_RGB10},
+ {0xa0, 0x58, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf4, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf4, ZC3XX_R110_RGB20},
+ {0xa0, 0xf4, ZC3XX_R111_RGB21},
+ {0xa0, 0x58, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x23, 0x0000},
+ {0xaa, 0x24, 0x00aa},
+ {0xaa, 0x25, 0x00e6},
+ {0xaa, 0x21, 0x003f},
+ {0xa0, 0x01, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x55, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xcc, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x18, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x6a, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x3f, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xa5, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xf0, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x40, ZC3XX_R118_BGAIN},
+ {}
+};
+static const struct usb_action cs2102_50HZ[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x0f, 0x008c}, /* 00,0f,8c,aa */
+ {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+ {0xaa, 0x04, 0x00ac}, /* 00,04,ac,aa */
+ {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+ {0xaa, 0x11, 0x00ac}, /* 00,11,ac,aa */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+ {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+ {0xaa, 0x1d, 0x00ac}, /* 00,1d,ac,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
+ {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x42, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,42,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+ {0xa0, 0x8c, ZC3XX_R01D_HSYNC_0}, /* 00,1d,8c,cc */
+ {0xa0, 0xb0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,b0,cc */
+ {0xa0, 0xd0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,d0,cc */
+ {}
+};
+static const struct usb_action cs2102_50HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x0f, 0x0093}, /* 00,0f,93,aa */
+ {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+ {0xaa, 0x04, 0x00a1}, /* 00,04,a1,aa */
+ {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+ {0xaa, 0x11, 0x00a1}, /* 00,11,a1,aa */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+ {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+ {0xaa, 0x1d, 0x00a1}, /* 00,1d,a1,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
+ {0xa0, 0xf7, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f7,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+ {0xa0, 0x93, ZC3XX_R01D_HSYNC_0}, /* 00,1d,93,cc */
+ {0xa0, 0xb0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,b0,cc */
+ {0xa0, 0xd0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,d0,cc */
+ {}
+};
+static const struct usb_action cs2102_60HZ[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x0f, 0x005d}, /* 00,0f,5d,aa */
+ {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+ {0xaa, 0x04, 0x00aa}, /* 00,04,aa,aa */
+ {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+ {0xaa, 0x11, 0x00aa}, /* 00,11,aa,aa */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+ {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+ {0xaa, 0x1d, 0x00aa}, /* 00,1d,aa,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
+ {0xa0, 0xe4, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,e4,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3a,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+ {0xa0, 0x5d, ZC3XX_R01D_HSYNC_0}, /* 00,1d,5d,cc */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
+ {0xa0, 0xd0, 0x00c8}, /* 00,c8,d0,cc */
+ {}
+};
+static const struct usb_action cs2102_60HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x0f, 0x00b7}, /* 00,0f,b7,aa */
+ {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+ {0xaa, 0x04, 0x00be}, /* 00,04,be,aa */
+ {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+ {0xaa, 0x11, 0x00be}, /* 00,11,be,aa */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+ {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+ {0xaa, 0x1d, 0x00be}, /* 00,1d,be,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
+ {0xa0, 0xfc, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,fc,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x69, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,69,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+ {0xa0, 0xb7, ZC3XX_R01D_HSYNC_0}, /* 00,1d,b7,cc */
+ {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
+ {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */
+ {}
+};
+static const struct usb_action cs2102_NoFliker[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x0f, 0x0059}, /* 00,0f,59,aa */
+ {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+ {0xaa, 0x04, 0x0080}, /* 00,04,80,aa */
+ {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+ {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+ {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+ {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
+ {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0x59, ZC3XX_R01D_HSYNC_0}, /* 00,1d,59,cc */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */
+ {}
+};
+static const struct usb_action cs2102_NoFlikerScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x0f, 0x0059}, /* 00,0f,59,aa */
+ {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+ {0xaa, 0x04, 0x0080}, /* 00,04,80,aa */
+ {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+ {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+ {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+ {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
+ {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0x59, ZC3XX_R01D_HSYNC_0}, /* 00,1d,59,cc */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */
+ {}
+};
+
+/* CS2102_KOCOM */
+static const struct usb_action cs2102K_Initial[] = {
+ {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+ {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0a, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0b, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0c, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7c, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0d, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0xa3, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x03, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x08, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0e, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x78, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x01, 0x01b1},
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x60, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x4c, ZC3XX_R118_BGAIN},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */
+ {0xa0, 0x38, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x59, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x79, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x92, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x26, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x22, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf4, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf4, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf4, ZC3XX_R10D_RGB10},
+ {0xa0, 0x58, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf4, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf4, ZC3XX_R110_RGB20},
+ {0xa0, 0xf4, ZC3XX_R111_RGB21},
+ {0xa0, 0x58, ZC3XX_R112_RGB22},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+ {0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x04, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0x0f, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x19, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x1f, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x60, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x4c, ZC3XX_R118_BGAIN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {}
+};
+
+static const struct usb_action cs2102K_InitialScale[] = {
+ {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+ {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0a, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0b, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0c, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7b, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0d, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0xa3, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x03, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x08, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0e, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x78, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x01, 0x01b1},
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x60, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x4c, ZC3XX_R118_BGAIN},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */
+ {0xa0, 0x38, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x59, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x79, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x92, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x26, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x22, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf4, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf4, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf4, ZC3XX_R10D_RGB10},
+ {0xa0, 0x58, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf4, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf4, ZC3XX_R110_RGB20},
+ {0xa0, 0xf4, ZC3XX_R111_RGB21},
+ {0xa0, 0x58, ZC3XX_R112_RGB22},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+ {0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x04, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0x0f, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x19, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x1f, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x60, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x4c, ZC3XX_R118_BGAIN},
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+ {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0A, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0B, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0C, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7b, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0D, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0xA3, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x03, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x08, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0E, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x0C, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x78, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x01, 0x01b1},
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x60, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x4c, ZC3XX_R118_BGAIN},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */
+ {0xa0, 0x38, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x59, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x79, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x92, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x26, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x22, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf4, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf4, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf4, ZC3XX_R10D_RGB10},
+ {0xa0, 0x58, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf4, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf4, ZC3XX_R110_RGB20},
+ {0xa0, 0xf4, ZC3XX_R111_RGB21},
+ {0xa0, 0x58, ZC3XX_R112_RGB22},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+ {0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x04, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0x0f, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x19, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x1f, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x60, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x4c, ZC3XX_R118_BGAIN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0xd0, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0xd0, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x0a, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x0a, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x44, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x44, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7e, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7e, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {}
+};
+
+static const struct usb_action gc0305_Initial[] = { /* 640x480 */
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */
+ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
+ {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT}, /* 00,02,04,cc */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
+ {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc */
+ {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */
+ {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc */
+ {0xaa, 0x13, 0x0002}, /* 00,13,02,aa */
+ {0xaa, 0x15, 0x0003}, /* 00,15,03,aa */
+ {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */
+ {0xaa, 0x02, 0x0000}, /* 00,02,00,aa */
+ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */
+ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa */
+ {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */
+ {0xaa, 0x1f, 0x0008}, /* 00,1f,08,aa */
+ {0xaa, 0x21, 0x0012}, /* 00,21,12,aa */
+ {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc */
+ {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc */
+ {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc */
+ {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */
+ {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa */
+ {0xaa, 0x0b, 0x00b0}, /* 00,0b,b0,aa */
+ {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa */
+ {0xaa, 0x0d, 0x00b0}, /* 00,0d,b0,aa */
+ {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa */
+ {0xaa, 0x0f, 0x00b0}, /* 00,0f,b0,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x11, 0x00b0}, /* 00,11,b0,aa */
+ {0xaa, 0x16, 0x0001}, /* 00,16,01,aa */
+ {0xaa, 0x17, 0x00e6}, /* 00,17,e6,aa */
+ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa */
+ {0xaa, 0x19, 0x0086}, /* 00,19,86,aa */
+ {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */
+ {0xaa, 0x1b, 0x0020}, /* 00,1b,20,aa */
+ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc */
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+ {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc */
+ {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */
+ {0xa0, 0x85, ZC3XX_R18D_YTARGET}, /* 01,8d,85,cc */
+ {0xa0, 0x00, 0x011e}, /* 01,1e,00,cc */
+ {0xa0, 0x52, ZC3XX_R116_RGAIN}, /* 01,16,52,cc */
+ {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* 01,17,40,cc */
+ {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */
+ {0xa0, 0x03, ZC3XX_R113_RGB03}, /* 01,13,03,cc */
+ {}
+};
+static const struct usb_action gc0305_InitialScale[] = { /* 320x240 */
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */
+ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc */
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */
+ {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc */
+ {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */
+ {0xaa, 0x15, 0x0001}, /* 00,15,01,aa */
+ {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */
+ {0xaa, 0x02, 0x0000}, /* 00,02,00,aa */
+ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */
+ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa */
+ {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */
+ {0xaa, 0x1f, 0x0008}, /* 00,1f,08,aa */
+ {0xaa, 0x21, 0x0012}, /* 00,21,12,aa */
+ {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc */
+ {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc */
+ {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc */
+ {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */
+ {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa */
+ {0xaa, 0x0b, 0x00b0}, /* 00,0b,b0,aa */
+ {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa */
+ {0xaa, 0x0d, 0x00b0}, /* 00,0d,b0,aa */
+ {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa */
+ {0xaa, 0x0f, 0x00b0}, /* 00,0f,b0,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x11, 0x00b0}, /* 00,11,b0,aa */
+ {0xaa, 0x16, 0x0001}, /* 00,16,01,aa */
+ {0xaa, 0x17, 0x00e8}, /* 00,17,e8,aa */
+ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa */
+ {0xaa, 0x19, 0x0088}, /* 00,19,88,aa */
+ {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */
+ {0xaa, 0x1b, 0x0020}, /* 00,1b,20,aa */
+ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc */
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+ {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc */
+ {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */
+ {0xa0, 0x00, 0x011e}, /* 01,1e,00,cc */
+ {0xa0, 0x52, ZC3XX_R116_RGAIN}, /* 01,16,52,cc */
+ {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* 01,17,40,cc */
+ {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */
+ {0xa0, 0x03, ZC3XX_R113_RGB03}, /* 01,13,03,cc */
+ {}
+};
+static const struct usb_action gc0305_50HZ[] = {
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */
+ {0xaa, 0x84, 0x0038}, /* 00,84,38,aa */ /* win: 00,84,ec */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc */
+ {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */
+ /* win: 01,92,10 */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,8e,cc */
+ /* win: 01,97,ec */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc */
+ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+ {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,60,cc */
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */
+/* {0xa0, 0x85, ZC3XX_R18D_YTARGET}, * 01,8d,85,cc *
+ * if 640x480 */
+ {}
+};
+static const struct usb_action gc0305_60HZ[] = {
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
+ {0xaa, 0x84, 0x00ec}, /* 00,84,ec,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc */
+ {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0xec, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,ec,cc */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc */
+ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+ {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,60,cc */
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */
+ {0xa0, 0x80, ZC3XX_R18D_YTARGET}, /* 01,8d,80,cc */
+ {}
+};
+
+static const struct usb_action gc0305_NoFliker[] = {
+ {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc */
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
+ {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,00,cc */
+ {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,48,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc */
+ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc */
+ {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,60,cc */
+ {0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,03,cc */
+ {0xa0, 0x80, ZC3XX_R18D_YTARGET}, /* 01,8d,80,cc */
+ {}
+};
+
+/* play poker with registers at your own risk !! */
+static const struct usb_action hdcs2020xx_Initial[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ /* D0 ?? E0 did not start */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},
+ {0xa0, 0x08, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x08, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
+ {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+ {0xaa, 0x02, 0x0002},
+ {0xaa, 0x07, 0x0006},
+ {0xaa, 0x08, 0x0002},
+ {0xaa, 0x09, 0x0006},
+ {0xaa, 0x0a, 0x0001},
+ {0xaa, 0x0b, 0x0001},
+ {0xaa, 0x0c, 0x0008},
+ {0xaa, 0x0d, 0x0000},
+ {0xaa, 0x10, 0x0000},
+ {0xaa, 0x12, 0x0005},
+ {0xaa, 0x13, 0x0063},
+ {0xaa, 0x15, 0x0070},
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x70, ZC3XX_R18D_YTARGET},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x04, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x07, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x11, ZC3XX_R120_GAMMA00}, /* gamma ~4 */
+ {0xa0, 0x37, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x58, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x79, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x91, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xa6, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xb8, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xc7, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xd3, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xde, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xe6, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xed, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xf3, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xf8, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xfb, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x26, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x23, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+
+ {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf5, ZC3XX_R10B_RGB01},
+ {0xa0, 0xff, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf9, ZC3XX_R10D_RGB10},
+ {0xa0, 0x51, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf5, ZC3XX_R10F_RGB12},
+ {0xa0, 0xfb, ZC3XX_R110_RGB20},
+ {0xa0, 0xed, ZC3XX_R111_RGB21},
+ {0xa0, 0x5f, ZC3XX_R112_RGB22},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
+ {0xaa, 0x20, 0x0004},
+ {0xaa, 0x21, 0x003d},
+ {0xaa, 0x03, 0x0041},
+ {0xaa, 0x04, 0x0010},
+ {0xaa, 0x05, 0x003d},
+ {0xaa, 0x0e, 0x0001},
+ {0xaa, 0x0f, 0x0000},
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x9b, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x41, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xad, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0195},
+ {0xa1, 0x01, 0x0196},
+ {0xa1, 0x01, 0x0197},
+ {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x1d, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x85, ZC3XX_R118_BGAIN},
+ {0xa1, 0x01, 0x0116},
+ {0xa1, 0x01, 0x0118},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x1d, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x85, ZC3XX_R118_BGAIN},
+ {0xa1, 0x01, 0x0116},
+ {0xa1, 0x01, 0x0118},
+/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
+ {0xa0, 0x00, 0x0007},
+ {}
+};
+
+static const struct usb_action hdcs2020xx_InitialScale[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
+ {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+ {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},
+ {0xaa, 0x02, 0x0002},
+ {0xaa, 0x07, 0x0006},
+ {0xaa, 0x08, 0x0002},
+ {0xaa, 0x09, 0x0006},
+ {0xaa, 0x0a, 0x0001},
+ {0xaa, 0x0b, 0x0001},
+ {0xaa, 0x0c, 0x0008},
+ {0xaa, 0x0d, 0x0000},
+ {0xaa, 0x10, 0x0000},
+ {0xaa, 0x12, 0x0005},
+ {0xaa, 0x13, 0x0063},
+ {0xaa, 0x15, 0x0070},
+ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x70, ZC3XX_R18D_YTARGET},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x04, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x07, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x11, ZC3XX_R120_GAMMA00}, /* gamma ~4*/
+ {0xa0, 0x37, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x58, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x79, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x91, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xa6, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xb8, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xc7, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xd3, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xde, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xe6, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xed, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xf3, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xf8, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xfb, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x26, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x23, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x60, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xff, ZC3XX_R10B_RGB01},
+ {0xa0, 0xff, ZC3XX_R10C_RGB02},
+ {0xa0, 0xff, ZC3XX_R10D_RGB10},
+ {0xa0, 0x60, ZC3XX_R10E_RGB11},
+ {0xa0, 0xff, ZC3XX_R10F_RGB12},
+ {0xa0, 0xff, ZC3XX_R110_RGB20},
+ {0xa0, 0xff, ZC3XX_R111_RGB21},
+ {0xa0, 0x60, ZC3XX_R112_RGB22},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
+ {0xaa, 0x20, 0x0002},
+ {0xaa, 0x21, 0x001b},
+ {0xaa, 0x03, 0x0044},
+ {0xaa, 0x04, 0x0008},
+ {0xaa, 0x05, 0x001b},
+ {0xaa, 0x0e, 0x0001},
+ {0xaa, 0x0f, 0x0000},
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x4d, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x44, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xad, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xeb, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0195},
+ {0xa1, 0x01, 0x0196},
+ {0xa1, 0x01, 0x0197},
+ {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x1d, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x99, ZC3XX_R118_BGAIN},
+ {0xa1, 0x01, 0x0116},
+ {0xa1, 0x01, 0x0118},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x1d, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x99, ZC3XX_R118_BGAIN},
+/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
+ {0xa0, 0x00, 0x0007},
+/* {0xa0, 0x18, 0x00fe}, */
+ {}
+};
+static const struct usb_action hdcs2020xb_Initial[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* qtable 0x05 */
+ {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+ {0xaa, 0x1c, 0x0000},
+ {0xaa, 0x0a, 0x0001},
+ {0xaa, 0x0b, 0x0006},
+ {0xaa, 0x0c, 0x007b},
+ {0xaa, 0x0d, 0x00a7},
+ {0xaa, 0x03, 0x00fb},
+ {0xaa, 0x05, 0x0000},
+ {0xaa, 0x06, 0x0003},
+ {0xaa, 0x09, 0x0008},
+
+ {0xaa, 0x0f, 0x0018}, /* set sensor gain */
+ {0xaa, 0x10, 0x0018},
+ {0xaa, 0x11, 0x0018},
+ {0xaa, 0x12, 0x0018},
+
+ {0xaa, 0x15, 0x004e},
+ {0xaa, 0x1c, 0x0004},
+ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x70, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x40, ZC3XX_R118_BGAIN},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */
+ {0xa0, 0x38, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x59, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x79, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x92, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x26, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x22, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+
+ {0xa0, 0x66, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xed, ZC3XX_R10B_RGB01},
+ {0xa0, 0xed, ZC3XX_R10C_RGB02},
+ {0xa0, 0xed, ZC3XX_R10D_RGB10},
+ {0xa0, 0x66, ZC3XX_R10E_RGB11},
+ {0xa0, 0xed, ZC3XX_R10F_RGB12},
+ {0xa0, 0xed, ZC3XX_R110_RGB20},
+ {0xa0, 0xed, ZC3XX_R111_RGB21},
+ {0xa0, 0x66, ZC3XX_R112_RGB22},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x13, 0x0031},
+ {0xaa, 0x14, 0x0001},
+ {0xaa, 0x0e, 0x0004},
+ {0xaa, 0x19, 0x00cd},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 0x14 */
+ {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x04, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0x18, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x41, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x40, ZC3XX_R118_BGAIN},
+ {}
+};
+static const struct usb_action hdcs2020xb_InitialScale[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+ {0xaa, 0x1c, 0x0000},
+ {0xaa, 0x0a, 0x0001},
+ {0xaa, 0x0b, 0x0006},
+ {0xaa, 0x0c, 0x007a},
+ {0xaa, 0x0d, 0x00a7},
+ {0xaa, 0x03, 0x00fb},
+ {0xaa, 0x05, 0x0000},
+ {0xaa, 0x06, 0x0003},
+ {0xaa, 0x09, 0x0008},
+ {0xaa, 0x0f, 0x0018}, /* original setting */
+ {0xaa, 0x10, 0x0018},
+ {0xaa, 0x11, 0x0018},
+ {0xaa, 0x12, 0x0018},
+ {0xaa, 0x15, 0x004e},
+ {0xaa, 0x1c, 0x0004},
+ {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x70, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x40, ZC3XX_R118_BGAIN},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */
+ {0xa0, 0x38, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x59, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x79, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x92, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x26, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x22, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x66, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xed, ZC3XX_R10B_RGB01},
+ {0xa0, 0xed, ZC3XX_R10C_RGB02},
+ {0xa0, 0xed, ZC3XX_R10D_RGB10},
+ {0xa0, 0x66, ZC3XX_R10E_RGB11},
+ {0xa0, 0xed, ZC3XX_R10F_RGB12},
+ {0xa0, 0xed, ZC3XX_R110_RGB20},
+ {0xa0, 0xed, ZC3XX_R111_RGB21},
+ {0xa0, 0x66, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ /**** set exposure ***/
+ {0xaa, 0x13, 0x0031},
+ {0xaa, 0x14, 0x0001},
+ {0xaa, 0x0e, 0x0004},
+ {0xaa, 0x19, 0x00cd},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x04, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0x18, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x41, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x40, ZC3XX_R118_BGAIN},
+ {}
+};
+static const struct usb_action hdcs2020b_50HZ[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x13, 0x0018}, /* 00,13,18,aa */
+ {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */
+ {0xaa, 0x0e, 0x0005}, /* 00,0e,05,aa */
+ {0xaa, 0x19, 0x001f}, /* 00,19,1f,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */
+ {0xa0, 0x76, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,76,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x46, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,46,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+ {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,28,cc */
+ {0xa0, 0x05, ZC3XX_R01D_HSYNC_0}, /* 00,1d,05,cc */
+ {0xa0, 0x1a, ZC3XX_R01E_HSYNC_1}, /* 00,1e,1a,cc */
+ {0xa0, 0x2f, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2f,cc */
+ {}
+};
+static const struct usb_action hdcs2020b_60HZ[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x13, 0x0031}, /* 00,13,31,aa */
+ {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */
+ {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */
+ {0xaa, 0x19, 0x00cd}, /* 00,19,cd,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */
+ {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,62,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3d,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+ {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,28,cc */
+ {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, /* 00,1d,04,cc */
+ {0xa0, 0x18, ZC3XX_R01E_HSYNC_1}, /* 00,1e,18,cc */
+ {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2c,cc */
+ {}
+};
+static const struct usb_action hdcs2020b_NoFliker[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x13, 0x0010}, /* 00,13,10,aa */
+ {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */
+ {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */
+ {0xaa, 0x19, 0x0000}, /* 00,19,00,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */
+ {0xa0, 0x70, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,70,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, /* 00,1d,04,cc */
+ {0xa0, 0x17, ZC3XX_R01E_HSYNC_1}, /* 00,1e,17,cc */
+ {0xa0, 0x2a, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2a,cc */
+ {}
+};
+
+static const struct usb_action hv7131bxx_Initial[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xaa, 0x30, 0x002d},
+ {0xaa, 0x01, 0x0005},
+ {0xaa, 0x11, 0x0000},
+ {0xaa, 0x13, 0x0001}, /* {0xaa, 0x13, 0x0000}, */
+ {0xaa, 0x14, 0x0001},
+ {0xaa, 0x15, 0x00e8},
+ {0xaa, 0x16, 0x0002},
+ {0xaa, 0x17, 0x0086},
+ {0xaa, 0x31, 0x0038},
+ {0xaa, 0x32, 0x0038},
+ {0xaa, 0x33, 0x0038},
+ {0xaa, 0x5b, 0x0001},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x68, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0xc0, 0x019b},
+ {0xa0, 0xa0, 0x019c},
+ {0xa0, 0x02, ZC3XX_R188_MINGAIN},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xaa, 0x02, 0x0080}, /* {0xaa, 0x02, 0x0090}; */
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
+ {0xa1, 0x01, 0x0091},
+ {0xa1, 0x01, 0x0095},
+ {0xa1, 0x01, 0x0096},
+
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+
+ {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf8, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf8, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf8, ZC3XX_R10D_RGB10},
+ {0xa0, 0x50, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf8, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf8, ZC3XX_R110_RGB20},
+ {0xa0, 0xf8, ZC3XX_R111_RGB21},
+ {0xa0, 0x50, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x25, 0x0007},
+ {0xaa, 0x26, 0x00a1},
+ {0xaa, 0x27, 0x0020},
+ {0xaa, 0x20, 0x0000},
+ {0xaa, 0x21, 0x00a0},
+ {0xaa, 0x22, 0x0016},
+ {0xaa, 0x23, 0x0040},
+
+ {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2F */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 4d */
+ {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x07, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x16, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x40, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa1, 0x01, 0x001d},
+ {0xa1, 0x01, 0x001e},
+ {0xa1, 0x01, 0x001f},
+ {0xa1, 0x01, 0x0020},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x40, ZC3XX_R118_BGAIN},
+/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
+ {}
+};
+
+static const struct usb_action hv7131bxx_InitialScale[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xaa, 0x30, 0x002d},
+ {0xaa, 0x01, 0x0005},
+ {0xaa, 0x11, 0x0001},
+ {0xaa, 0x13, 0x0000}, /* {0xaa, 0x13, 0x0001}; */
+ {0xaa, 0x14, 0x0001},
+ {0xaa, 0x15, 0x00e6},
+ {0xaa, 0x16, 0x0002},
+ {0xaa, 0x17, 0x0086},
+ {0xaa, 0x31, 0x0038},
+ {0xaa, 0x32, 0x0038},
+ {0xaa, 0x33, 0x0038},
+ {0xaa, 0x5b, 0x0001},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x70, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0xc0, 0x019b},
+ {0xa0, 0xa0, 0x019c},
+ {0xa0, 0x02, ZC3XX_R188_MINGAIN},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xaa, 0x02, 0x0090}, /* {0xaa, 0x02, 0x0080}, */
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
+ {0xa1, 0x01, 0x0091},
+ {0xa1, 0x01, 0x0095},
+ {0xa1, 0x01, 0x0096},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+
+ {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf8, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf8, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf8, ZC3XX_R10D_RGB10},
+ {0xa0, 0x50, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf8, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf8, ZC3XX_R110_RGB20},
+ {0xa0, 0xf8, ZC3XX_R111_RGB21},
+ {0xa0, 0x50, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x25, 0x0007},
+ {0xaa, 0x26, 0x00a1},
+ {0xaa, 0x27, 0x0020},
+ {0xaa, 0x20, 0x0000},
+ {0xaa, 0x21, 0x0040},
+ {0xaa, 0x22, 0x0013},
+ {0xaa, 0x23, 0x004c},
+ {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2f */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 4d */
+ {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 60 */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0x40, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x13, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x4c, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa1, 0x01, 0x001d},
+ {0xa1, 0x01, 0x001e},
+ {0xa1, 0x01, 0x001f},
+ {0xa1, 0x01, 0x0020},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x40, ZC3XX_R118_BGAIN},
+/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
+ {}
+};
+
+static const struct usb_action hv7131cxx_Initial[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xaa, 0x01, 0x000c},
+ {0xaa, 0x11, 0x0000},
+ {0xaa, 0x13, 0x0000},
+ {0xaa, 0x14, 0x0001},
+ {0xaa, 0x15, 0x00e8},
+ {0xaa, 0x16, 0x0002},
+ {0xaa, 0x17, 0x0088},
+
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x89, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0xc0, 0x019b},
+ {0xa0, 0xa0, 0x019c},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
+ {0xa1, 0x01, 0x0091},
+ {0xa1, 0x01, 0x0095},
+ {0xa1, 0x01, 0x0096},
+
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+
+ {0xa0, 0x60, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf0, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf0, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf0, ZC3XX_R10D_RGB10},
+ {0xa0, 0x60, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf0, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf0, ZC3XX_R110_RGB20},
+ {0xa0, 0xf0, ZC3XX_R111_RGB21},
+ {0xa0, 0x60, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x25, 0x0007},
+ {0xaa, 0x26, 0x0053},
+ {0xaa, 0x27, 0x0000},
+
+ {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2f */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 9b */
+ {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 80 */
+ {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x13, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa1, 0x01, 0x001d},
+ {0xa1, 0x01, 0x001e},
+ {0xa1, 0x01, 0x001f},
+ {0xa1, 0x01, 0x0020},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+
+static const struct usb_action hv7131cxx_InitialScale[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* diff */
+ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 1e0 */
+
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xaa, 0x01, 0x000c},
+ {0xaa, 0x11, 0x0000},
+ {0xaa, 0x13, 0x0000},
+ {0xaa, 0x14, 0x0001},
+ {0xaa, 0x15, 0x00e8},
+ {0xaa, 0x16, 0x0002},
+ {0xaa, 0x17, 0x0088},
+
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00 */
+
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x89, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0xc0, 0x019b},
+ {0xa0, 0xa0, 0x019c},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
+ /* read the i2c chips ident */
+ {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
+ {0xa1, 0x01, 0x0091},
+ {0xa1, 0x01, 0x0095},
+ {0xa1, 0x01, 0x0096},
+
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+
+ {0xa0, 0x60, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf0, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf0, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf0, ZC3XX_R10D_RGB10},
+ {0xa0, 0x60, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf0, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf0, ZC3XX_R110_RGB20},
+ {0xa0, 0xf0, ZC3XX_R111_RGB21},
+ {0xa0, 0x60, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x25, 0x0007},
+ {0xaa, 0x26, 0x0053},
+ {0xaa, 0x27, 0x0000},
+
+ {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2f */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 9b */
+ {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 80 */
+
+ {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW},
+
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x13, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa1, 0x01, 0x001d},
+ {0xa1, 0x01, 0x001e},
+ {0xa1, 0x01, 0x001f},
+ {0xa1, 0x01, 0x0020},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+
+static const struct usb_action icm105axx_Initial[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x0c, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x00, ZC3XX_R097_WINYSTARTHIGH},
+ {0xa0, 0x01, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R099_WINXSTARTHIGH},
+ {0xa0, 0x01, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x01, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x01, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xaa, 0x01, 0x0010},
+ {0xaa, 0x03, 0x0000},
+ {0xaa, 0x04, 0x0001},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0001},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0001},
+ {0xaa, 0x04, 0x0011},
+ {0xaa, 0x05, 0x00a0},
+ {0xaa, 0x06, 0x0001},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0002},
+ {0xaa, 0x04, 0x0013},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0001},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0003},
+ {0xaa, 0x04, 0x0015},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0004},
+ {0xaa, 0x04, 0x0017},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x000d},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0005},
+ {0xaa, 0x04, 0x0019},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0006},
+ {0xaa, 0x04, 0x0017},
+ {0xaa, 0x05, 0x0026},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0007},
+ {0xaa, 0x04, 0x0019},
+ {0xaa, 0x05, 0x0022},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0008},
+ {0xaa, 0x04, 0x0021},
+ {0xaa, 0x05, 0x00aa},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0009},
+ {0xaa, 0x04, 0x0023},
+ {0xaa, 0x05, 0x00aa},
+ {0xaa, 0x06, 0x000d},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x000a},
+ {0xaa, 0x04, 0x0025},
+ {0xaa, 0x05, 0x00aa},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x000b},
+ {0xaa, 0x04, 0x00ec},
+ {0xaa, 0x05, 0x002e},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x000c},
+ {0xaa, 0x04, 0x00fa},
+ {0xaa, 0x05, 0x002a},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x07, 0x000d},
+ {0xaa, 0x01, 0x0005},
+ {0xaa, 0x94, 0x0002},
+ {0xaa, 0x90, 0x0000},
+ {0xaa, 0x91, 0x001f},
+ {0xaa, 0x10, 0x0064},
+ {0xaa, 0x9b, 0x00f0},
+ {0xaa, 0x9c, 0x0002},
+ {0xaa, 0x14, 0x001a},
+ {0xaa, 0x20, 0x0080},
+ {0xaa, 0x22, 0x0080},
+ {0xaa, 0x24, 0x0080},
+ {0xaa, 0x26, 0x0080},
+ {0xaa, 0x00, 0x0084},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xaa, 0xa8, 0x00c0},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x40, ZC3XX_R118_BGAIN},
+ {0xa1, 0x01, 0x0008},
+
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x52, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf7, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf7, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf7, ZC3XX_R10D_RGB10},
+ {0xa0, 0x52, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf7, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf7, ZC3XX_R110_RGB20},
+ {0xa0, 0xf7, ZC3XX_R111_RGB21},
+ {0xa0, 0x52, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x0d, 0x0003},
+ {0xaa, 0x0c, 0x008c},
+ {0xaa, 0x0e, 0x0095},
+ {0xaa, 0x0f, 0x0002},
+ {0xaa, 0x1c, 0x0094},
+ {0xaa, 0x1d, 0x0002},
+ {0xaa, 0x20, 0x0080},
+ {0xaa, 0x22, 0x0080},
+ {0xaa, 0x24, 0x0080},
+ {0xaa, 0x26, 0x0080},
+ {0xaa, 0x00, 0x0084},
+ {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+ {0xa0, 0x94, ZC3XX_R0A4_EXPOSURETIMELOW},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x84, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0xe3, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xec, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xf5, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0xc0, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x40, ZC3XX_R118_BGAIN},
+ {}
+};
+
+static const struct usb_action icm105axx_InitialScale[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x0c, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x00, ZC3XX_R097_WINYSTARTHIGH},
+ {0xa0, 0x02, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R099_WINXSTARTHIGH},
+ {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x02, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
+ {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+ {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},
+ {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xaa, 0x01, 0x0010},
+ {0xaa, 0x03, 0x0000},
+ {0xaa, 0x04, 0x0001},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0001},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0001},
+ {0xaa, 0x04, 0x0011},
+ {0xaa, 0x05, 0x00a0},
+ {0xaa, 0x06, 0x0001},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0002},
+ {0xaa, 0x04, 0x0013},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0001},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0003},
+ {0xaa, 0x04, 0x0015},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0004},
+ {0xaa, 0x04, 0x0017},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x000d},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0005},
+ {0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x19, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa1, 0x01, 0x0091},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0006},
+ {0xaa, 0x04, 0x0017},
+ {0xaa, 0x05, 0x0026},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0007},
+ {0xaa, 0x04, 0x0019},
+ {0xaa, 0x05, 0x0022},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0008},
+ {0xaa, 0x04, 0x0021},
+ {0xaa, 0x05, 0x00aa},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0009},
+ {0xaa, 0x04, 0x0023},
+ {0xaa, 0x05, 0x00aa},
+ {0xaa, 0x06, 0x000d},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x000a},
+ {0xaa, 0x04, 0x0025},
+ {0xaa, 0x05, 0x00aa},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x000b},
+ {0xaa, 0x04, 0x00ec},
+ {0xaa, 0x05, 0x002e},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x000c},
+ {0xaa, 0x04, 0x00fa},
+ {0xaa, 0x05, 0x002a},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x07, 0x000d},
+ {0xaa, 0x01, 0x0005},
+ {0xaa, 0x94, 0x0002},
+ {0xaa, 0x90, 0x0000},
+ {0xaa, 0x91, 0x0010},
+ {0xaa, 0x10, 0x0064},
+ {0xaa, 0x9b, 0x00f0},
+ {0xaa, 0x9c, 0x0002},
+ {0xaa, 0x14, 0x001a},
+ {0xaa, 0x20, 0x0080},
+ {0xaa, 0x22, 0x0080},
+ {0xaa, 0x24, 0x0080},
+ {0xaa, 0x26, 0x0080},
+ {0xaa, 0x00, 0x0084},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xaa, 0xa8, 0x0080},
+ {0xa0, 0x78, ZC3XX_R18D_YTARGET},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x40, ZC3XX_R118_BGAIN},
+ {0xa1, 0x01, 0x0008},
+
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+
+ {0xa0, 0x52, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf7, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf7, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf7, ZC3XX_R10D_RGB10},
+ {0xa0, 0x52, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf7, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf7, ZC3XX_R110_RGB20},
+ {0xa0, 0xf7, ZC3XX_R111_RGB21},
+ {0xa0, 0x52, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x0d, 0x0003},
+ {0xaa, 0x0c, 0x0020},
+ {0xaa, 0x0e, 0x000e},
+ {0xaa, 0x0f, 0x0002},
+ {0xaa, 0x1c, 0x000d},
+ {0xaa, 0x1d, 0x0002},
+ {0xaa, 0x20, 0x0080},
+ {0xaa, 0x22, 0x0080},
+ {0xaa, 0x24, 0x0080},
+ {0xaa, 0x26, 0x0080},
+ {0xaa, 0x00, 0x0084},
+ {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+ {0xa0, 0x0d, ZC3XX_R0A4_EXPOSURETIMELOW},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x1a, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x4b, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0xc8, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xd8, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xea, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x40, ZC3XX_R118_BGAIN},
+ {}
+};
+static const struct usb_action icm105a_50HZ[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+ {0xaa, 0x0c, 0x0020}, /* 00,0c,20,aa */
+ {0xaa, 0x0e, 0x000e}, /* 00,0e,0e,aa */
+ {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+ {0xaa, 0x1c, 0x000d}, /* 00,1c,0d,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+ {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+ {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+ {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+ {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+ {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */
+ {0xa0, 0x0d, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,0d,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+ {0xa0, 0x1a, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,1a,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x4b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,4b,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+ {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */
+ {0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c8,cc */
+ {0xa0, 0xd8, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d8,cc */
+ {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {}
+};
+static const struct usb_action icm105a_50HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+ {0xaa, 0x0c, 0x008c}, /* 00,0c,8c,aa */
+ {0xaa, 0x0e, 0x0095}, /* 00,0e,95,aa */
+ {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+ {0xaa, 0x1c, 0x0094}, /* 00,1c,94,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+ {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+ {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+ {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+ {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+ {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */
+ {0xa0, 0x94, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,94,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+ {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x84, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,84,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+ {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */
+ {0xa0, 0xe3, ZC3XX_R01D_HSYNC_0}, /* 00,1d,e3,cc */
+ {0xa0, 0xec, ZC3XX_R01E_HSYNC_1}, /* 00,1e,ec,cc */
+ {0xa0, 0xf5, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f5,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */
+ {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */
+ {}
+};
+static const struct usb_action icm105a_60HZ[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+ {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */
+ {0xaa, 0x0e, 0x000d}, /* 00,0e,0d,aa */
+ {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+ {0xaa, 0x1c, 0x0008}, /* 00,1c,08,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+ {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+ {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+ {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+ {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+ {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */
+ {0xa0, 0x08, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,08,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+ {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x41, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,41,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+ {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */
+ {0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */
+ {0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */
+ {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {}
+};
+static const struct usb_action icm105a_60HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+ {0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */
+ {0xaa, 0x0e, 0x0086}, /* 00,0e,86,aa */
+ {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+ {0xaa, 0x1c, 0x0085}, /* 00,1c,85,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+ {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+ {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+ {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+ {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+ {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */
+ {0xa0, 0x85, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,85,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+ {0xa0, 0x08, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,08,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,81,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+ {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */
+ {0xa0, 0xc2, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c2,cc */
+ {0xa0, 0xd6, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d6,cc */
+ {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */
+ {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */
+ {}
+};
+static const struct usb_action icm105a_NoFliker[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+ {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */
+ {0xaa, 0x0e, 0x000d}, /* 00,0e,0d,aa */
+ {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+ {0xaa, 0x1c, 0x0000}, /* 00,1c,00,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+ {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+ {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+ {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+ {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+ {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */
+ {0xa0, 0x00, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,00,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+ {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */
+ {0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */
+ {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {}
+};
+static const struct usb_action icm105a_NoFlikerScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+ {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */
+ {0xaa, 0x0e, 0x0081}, /* 00,0e,81,aa */
+ {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+ {0xaa, 0x1c, 0x0080}, /* 00,1c,80,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+ {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+ {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+ {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+ {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+ {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */
+ {0xa0, 0x80, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,80,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+ {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */
+ {0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */
+ {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */
+ {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */
+ {}
+};
+
+static const struct usb_action MC501CB_InitialScale[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc */
+ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+ {0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
+ {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */
+ {0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */
+ {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */
+ {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */
+ {0xa0, 0x33, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,33,cc */
+ {0xa0, 0x34, ZC3XX_R087_EXPTIMEMID}, /* 00,87,34,cc */
+ {0xa0, 0x35, ZC3XX_R088_EXPTIMELOW}, /* 00,88,35,cc */
+ {0xa0, 0xb0, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,b0,cc */
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+ {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */
+ {0xaa, 0x01, 0x0003}, /* 00,01,03,aa */
+ {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */
+ {0xaa, 0x03, 0x0000}, /* 00,03,00,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
+ {0xaa, 0x12, 0x0000}, /* 00,12,00,aa */
+ {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */
+ {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */
+ {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */
+ {0xaa, 0x16, 0x0000}, /* 00,16,00,aa */
+ {0xaa, 0x17, 0x0001}, /* 00,17,01,aa */
+ {0xaa, 0x18, 0x00de}, /* 00,18,de,aa */
+ {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */
+ {0xaa, 0x1a, 0x0086}, /* 00,1a,86,aa */
+ {0xaa, 0x20, 0x00a8}, /* 00,20,a8,aa */
+ {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */
+ {0xaa, 0x23, 0x0000}, /* 00,23,00,aa */
+ {0xaa, 0x24, 0x0000}, /* 00,24,00,aa */
+ {0xaa, 0x40, 0x0033}, /* 00,40,33,aa */
+ {0xaa, 0x41, 0x0077}, /* 00,41,77,aa */
+ {0xaa, 0x42, 0x0053}, /* 00,42,53,aa */
+ {0xaa, 0x43, 0x00b0}, /* 00,43,b0,aa */
+ {0xaa, 0x4b, 0x0001}, /* 00,4b,01,aa */
+ {0xaa, 0x72, 0x0020}, /* 00,72,20,aa */
+ {0xaa, 0x73, 0x0000}, /* 00,73,00,aa */
+ {0xaa, 0x80, 0x0000}, /* 00,80,00,aa */
+ {0xaa, 0x85, 0x0050}, /* 00,85,50,aa */
+ {0xaa, 0x91, 0x0070}, /* 00,91,70,aa */
+ {0xaa, 0x92, 0x0072}, /* 00,92,72,aa */
+ {0xaa, 0x03, 0x0001}, /* 00,03,01,aa */
+ {0xaa, 0x10, 0x00a0}, /* 00,10,a0,aa */
+ {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */
+ {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */
+ {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */
+ {0xaa, 0xa0, ZC3XX_R01A_LASTFRAMESTATE}, /* 00,a0,1a,aa */
+ {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */
+ {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */
+ {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */
+ {0xaa, 0xa4, 0x0010}, /* 00,a4,10,aa */
+ {0xaa, 0xa5, 0x0020}, /* 00,a5,20,aa */
+ {0xaa, 0xb1, 0x0044}, /* 00,b1,44,aa */
+ {0xaa, 0xd0, 0x0001}, /* 00,d0,01,aa */
+ {0xaa, 0xd1, 0x0085}, /* 00,d1,85,aa */
+ {0xaa, 0xd2, 0x0080}, /* 00,d2,80,aa */
+ {0xaa, 0xd3, 0x0080}, /* 00,d3,80,aa */
+ {0xaa, 0xd4, 0x0080}, /* 00,d4,80,aa */
+ {0xaa, 0xd5, 0x0080}, /* 00,d5,80,aa */
+ {0xaa, 0xc0, 0x00c3}, /* 00,c0,c3,aa */
+ {0xaa, 0xc2, 0x0044}, /* 00,c2,44,aa */
+ {0xaa, 0xc4, 0x0040}, /* 00,c4,40,aa */
+ {0xaa, 0xc5, 0x0020}, /* 00,c5,20,aa */
+ {0xaa, 0xc6, 0x0008}, /* 00,c6,08,aa */
+ {0xaa, 0x03, 0x0004}, /* 00,03,04,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x40, 0x0030}, /* 00,40,30,aa */
+ {0xaa, 0x41, 0x0020}, /* 00,41,20,aa */
+ {0xaa, 0x42, 0x002d}, /* 00,42,2d,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x1c, 0x0050}, /* 00,1C,50,aa */
+ {0xaa, 0x11, 0x0081}, /* 00,11,81,aa */
+ {0xaa, 0x3b, 0x001d}, /* 00,3b,1D,aa */
+ {0xaa, 0x3c, 0x004c}, /* 00,3c,4C,aa */
+ {0xaa, 0x3d, 0x0018}, /* 00,3d,18,aa */
+ {0xaa, 0x3e, 0x006a}, /* 00,3e,6A,aa */
+ {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */
+ {0xaa, 0x52, 0x00ff}, /* 00,52,FF,aa */
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
+ {0xaa, 0x03, 0x0002}, /* 00,03,02,aa */
+ {0xaa, 0x51, 0x0027}, /* 00,51,27,aa */
+ {0xaa, 0x52, 0x0020}, /* 00,52,20,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x50, 0x0010}, /* 00,50,10,aa */
+ {0xaa, 0x51, 0x0010}, /* 00,51,10,aa */
+ {0xaa, 0x54, 0x0010}, /* 00,54,10,aa */
+ {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */
+ {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */
+ {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */
+
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
+ {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
+ {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_Initial[] = { /* 320x240 */
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */
+ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+ {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
+ {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */
+ {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d8,cc */
+ {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */
+ {0xa0, 0x33, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,33,cc */
+ {0xa0, 0x34, ZC3XX_R087_EXPTIMEMID}, /* 00,87,34,cc */
+ {0xa0, 0x35, ZC3XX_R088_EXPTIMELOW}, /* 00,88,35,cc */
+ {0xa0, 0xb0, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,b0,cc */
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+ {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */
+ {0xaa, 0x01, 0x0003}, /* 00,01,03,aa */
+ {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */
+ {0xaa, 0x03, 0x0000}, /* 00,03,00,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
+ {0xaa, 0x12, 0x0000}, /* 00,12,00,aa */
+ {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */
+ {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */
+ {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */
+ {0xaa, 0x16, 0x0000}, /* 00,16,00,aa */
+ {0xaa, 0x17, 0x0001}, /* 00,17,01,aa */
+ {0xaa, 0x18, 0x00d8}, /* 00,18,d8,aa */
+ {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */
+ {0xaa, 0x1a, 0x0088}, /* 00,1a,88,aa */
+ {0xaa, 0x20, 0x00a8}, /* 00,20,a8,aa */
+ {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */
+ {0xaa, 0x23, 0x0000}, /* 00,23,00,aa */
+ {0xaa, 0x24, 0x0000}, /* 00,24,00,aa */
+ {0xaa, 0x40, 0x0033}, /* 00,40,33,aa */
+ {0xaa, 0x41, 0x0077}, /* 00,41,77,aa */
+ {0xaa, 0x42, 0x0053}, /* 00,42,53,aa */
+ {0xaa, 0x43, 0x00b0}, /* 00,43,b0,aa */
+ {0xaa, 0x4b, 0x0001}, /* 00,4b,01,aa */
+ {0xaa, 0x72, 0x0020}, /* 00,72,20,aa */
+ {0xaa, 0x73, 0x0000}, /* 00,73,00,aa */
+ {0xaa, 0x80, 0x0000}, /* 00,80,00,aa */
+ {0xaa, 0x85, 0x0050}, /* 00,85,50,aa */
+ {0xaa, 0x91, 0x0070}, /* 00,91,70,aa */
+ {0xaa, 0x92, 0x0072}, /* 00,92,72,aa */
+ {0xaa, 0x03, 0x0001}, /* 00,03,01,aa */
+ {0xaa, 0x10, 0x00a0}, /* 00,10,a0,aa */
+ {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */
+ {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */
+ {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */
+ {0xaa, 0xa0, ZC3XX_R01A_LASTFRAMESTATE}, /* 00,a0,1a,aa */
+ {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */
+ {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */
+ {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */
+ {0xaa, 0xa4, 0x0010}, /* 00,a4,10,aa */
+ {0xaa, 0xa5, 0x0020}, /* 00,a5,20,aa */
+ {0xaa, 0xb1, 0x0044}, /* 00,b1,44,aa */
+ {0xaa, 0xd0, 0x0001}, /* 00,d0,01,aa */
+ {0xaa, 0xd1, 0x0085}, /* 00,d1,85,aa */
+ {0xaa, 0xd2, 0x0080}, /* 00,d2,80,aa */
+ {0xaa, 0xd3, 0x0080}, /* 00,d3,80,aa */
+ {0xaa, 0xd4, 0x0080}, /* 00,d4,80,aa */
+ {0xaa, 0xd5, 0x0080}, /* 00,d5,80,aa */
+ {0xaa, 0xc0, 0x00c3}, /* 00,c0,c3,aa */
+ {0xaa, 0xc2, 0x0044}, /* 00,c2,44,aa */
+ {0xaa, 0xc4, 0x0040}, /* 00,c4,40,aa */
+ {0xaa, 0xc5, 0x0020}, /* 00,c5,20,aa */
+ {0xaa, 0xc6, 0x0008}, /* 00,c6,08,aa */
+ {0xaa, 0x03, 0x0004}, /* 00,03,04,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x40, 0x0030}, /* 00,40,30,aa */
+ {0xaa, 0x41, 0x0020}, /* 00,41,20,aa */
+ {0xaa, 0x42, 0x002d}, /* 00,42,2d,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x1c, 0x0050}, /* 00,1c,50,aa */
+ {0xaa, 0x11, 0x0081}, /* 00,11,81,aa */
+ {0xaa, 0x3b, 0x003a}, /* 00,3b,3A,aa */
+ {0xaa, 0x3c, 0x0098}, /* 00,3c,98,aa */
+ {0xaa, 0x3d, 0x0030}, /* 00,3d,30,aa */
+ {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
+ {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */
+ {0xaa, 0x52, 0x00ff}, /* 00,52,FF,aa */
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
+ {0xaa, 0x03, 0x0002}, /* 00,03,02,aa */
+ {0xaa, 0x51, 0x004e}, /* 00,51,4E,aa */
+ {0xaa, 0x52, 0x0041}, /* 00,52,41,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x50, 0x0010}, /* 00,50,10,aa */
+ {0xaa, 0x51, 0x0010}, /* 00,51,10,aa */
+ {0xaa, 0x54, 0x0010}, /* 00,54,10,aa */
+ {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */
+ {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */
+ {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
+ {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
+ {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_50HZ[] = {
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
+ {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
+ {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
+ {0xaa, 0x3c, 0x004c}, /* 00,3C,4C,aa */
+ {0xaa, 0x3d, 0x001d}, /* 00,3D,1D,aa */
+ {0xaa, 0x3e, 0x004c}, /* 00,3E,4C,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
+ {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */
+ {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_50HZScale[] = {
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
+ {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */
+ {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */
+ {0xaa, 0x3c, 0x0098}, /* 00,3C,98,aa */
+ {0xaa, 0x3d, 0x003a}, /* 00,3D,3A,aa */
+ {0xaa, 0x3e, 0x0098}, /* 00,3E,98,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
+ {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
+ {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_60HZ[] = {
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
+ {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
+ {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
+ {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */
+ {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */
+ {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
+ {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
+ {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_60HZScale[] = {
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
+ {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
+ {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
+ {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
+ {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */
+ {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
+ {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
+ {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_NoFliker[] = {
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
+ {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
+ {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
+ {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */
+ {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */
+ {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
+ {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
+ {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_NoFlikerScale[] = {
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
+ {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
+ {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
+ {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
+ {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */
+ {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */
+ {}
+};
+
+/* from zs211.inf - HKR,%OV7620%,Initial - 640x480 */
+static const struct usb_action OV7620_mode0[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+ {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, /* 00,02,40,cc */
+ {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+ {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,06,cc */
+ {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, /* 00,83,02,cc */
+ {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, /* 00,85,01,cc */
+ {0xa0, 0x80, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,80,cc */
+ {0xa0, 0x81, ZC3XX_R087_EXPTIMEMID}, /* 00,87,81,cc */
+ {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, /* 00,88,10,cc */
+ {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,a1,cc */
+ {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+ {0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
+ {0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */
+ {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */
+ {0xaa, 0x12, 0x0088}, /* 00,12,88,aa */
+ {0xaa, 0x12, 0x0048}, /* 00,12,48,aa */
+ {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */
+ {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
+ {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */
+ {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */
+ {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */
+ {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
+ {0xaa, 0x17, 0x0018}, /* 00,17,18,aa */
+ {0xaa, 0x18, 0x00ba}, /* 00,18,ba,aa */
+ {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */
+ {0xaa, 0x1a, 0x00f1}, /* 00,1a,f1,aa */
+ {0xaa, 0x20, 0x0040}, /* 00,20,40,aa */
+ {0xaa, 0x24, 0x0088}, /* 00,24,88,aa */
+ {0xaa, 0x25, 0x0078}, /* 00,25,78,aa */
+ {0xaa, 0x27, 0x00f6}, /* 00,27,f6,aa */
+ {0xaa, 0x28, 0x00a0}, /* 00,28,a0,aa */
+ {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+ {0xaa, 0x2a, 0x0083}, /* 00,2a,83,aa */
+ {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */
+ {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */
+ {0xaa, 0x74, 0x0020}, /* 00,74,20,aa */
+ {0xaa, 0x61, 0x0068}, /* 00,61,68,aa */
+ {0xaa, 0x64, 0x0088}, /* 00,64,88,aa */
+ {0xaa, 0x00, 0x0000}, /* 00,00,00,aa */
+ {0xaa, 0x06, 0x0080}, /* 00,06,80,aa */
+ {0xaa, 0x01, 0x0090}, /* 00,01,90,aa */
+ {0xaa, 0x02, 0x0030}, /* 00,02,30,aa */
+ {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,77,cc */
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+ {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+ {0xa0, 0x68, ZC3XX_R116_RGAIN}, /* 01,16,68,cc */
+ {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */
+ {0xa0, 0x40, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,40,cc */
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
+ {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,50,cc */
+ {}
+};
+
+/* from zs211.inf - HKR,%OV7620%,InitialScale - 320x240 */
+static const struct usb_action OV7620_mode1[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+ {0xa0, 0x50, ZC3XX_R002_CLOCKSELECT}, /* 00,02,50,cc */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */
+ /* mx change? */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+ {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,06,cc */
+ {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, /* 00,83,02,cc */
+ {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, /* 00,85,01,cc */
+ {0xa0, 0x80, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,80,cc */
+ {0xa0, 0x81, ZC3XX_R087_EXPTIMEMID}, /* 00,87,81,cc */
+ {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, /* 00,88,10,cc */
+ {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,a1,cc */
+ {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+ {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
+ {0xa0, 0xd6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d6,cc */
+ /* OV7648 00,9c,d8,cc */
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */
+ {0xaa, 0x12, 0x0088}, /* 00,12,88,aa */
+ {0xaa, 0x12, 0x0048}, /* 00,12,48,aa */
+ {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */
+ {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
+ {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */
+ {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */
+ {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */
+ {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
+ {0xaa, 0x24, 0x0088}, /* 00,24,88,aa */
+ {0xaa, 0x25, 0x0078}, /* 00,25,78,aa */
+ {0xaa, 0x17, 0x0018}, /* 00,17,18,aa */
+ {0xaa, 0x18, 0x00ba}, /* 00,18,ba,aa */
+ {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */
+ {0xaa, 0x1a, 0x00f2}, /* 00,1a,f2,aa */
+ {0xaa, 0x20, 0x0040}, /* 00,20,40,aa */
+ {0xaa, 0x27, 0x00f6}, /* 00,27,f6,aa */
+ {0xaa, 0x28, 0x00a0}, /* 00,28,a0,aa */
+ {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+ {0xaa, 0x2a, 0x0083}, /* 00,2a,83,aa */
+ {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */
+ {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */
+ {0xaa, 0x74, 0x0020}, /* 00,74,20,aa */
+ {0xaa, 0x61, 0x0068}, /* 00,61,68,aa */
+ {0xaa, 0x64, 0x0088}, /* 00,64,88,aa */
+ {0xaa, 0x00, 0x0000}, /* 00,00,00,aa */
+ {0xaa, 0x06, 0x0080}, /* 00,06,80,aa */
+ {0xaa, 0x01, 0x0090}, /* 00,01,90,aa */
+ {0xaa, 0x02, 0x0030}, /* 00,02,30,aa */
+ {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,77,cc */
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+ {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+ {0xa0, 0x68, ZC3XX_R116_RGAIN}, /* 01,16,68,cc */
+ {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */
+ {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,50,cc */
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
+ {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,50,cc */
+ {}
+};
+
+/* from zs211.inf - HKR,%OV7620%\AE,50HZ */
+static const struct usb_action OV7620_50HZ[] = {
+ {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
+ {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */
+ {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */
+ {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */
+ {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+ {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */
+ {0xaa, 0x10, 0x0082}, /* 00,10,82,aa */
+ {0xaa, 0x76, 0x0003}, /* 00,76,03,aa */
+/* {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, * 00,02,40,cc
+ if mode0 (640x480) */
+ {}
+};
+
+/* from zs211.inf - HKR,%OV7620%\AE,60HZ */
+static const struct usb_action OV7620_60HZ[] = {
+ {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
+ /* (bug in zs211.inf) */
+ {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */
+ {0xaa, 0x2b, 0x0000}, /* 00,2b,00,aa */
+ {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */
+ {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+ {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */
+ {0xaa, 0x10, 0x0020}, /* 00,10,20,aa */
+ {0xaa, 0x76, 0x0003}, /* 00,76,03,aa */
+/* {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, * 00,02,40,cc
+ * if mode0 (640x480) */
+/* ?? in gspca v1, it was
+ {0xa0, 0x00, 0x0039}, * 00,00,00,dd *
+ {0xa1, 0x01, 0x0037}, */
+ {}
+};
+
+/* from zs211.inf - HKR,%OV7620%\AE,NoFliker */
+static const struct usb_action OV7620_NoFliker[] = {
+ {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
+ /* (bug in zs211.inf) */
+ {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */
+ {0xaa, 0x2b, 0x0000}, /* 00,2b,00,aa */
+ {0xaa, 0x75, 0x008e}, /* 00,75,8e,aa */
+ {0xaa, 0x2d, 0x0001}, /* 00,2d,01,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+ {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,01,cc */
+/* {0xa0, 0x44, ZC3XX_R002_CLOCKSELECT}, * 00,02,44,cc
+ - if mode1 (320x240) */
+/* ?? was
+ {0xa0, 0x00, 0x0039}, * 00,00,00,dd *
+ {0xa1, 0x01, 0x0037}, */
+ {}
+};
+
+static const struct usb_action ov7630c_Initial[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xaa, 0x12, 0x0080},
+ {0xa0, 0x02, ZC3XX_R083_RGAINADDR},
+ {0xa0, 0x01, ZC3XX_R085_BGAINADDR},
+ {0xa0, 0x90, ZC3XX_R086_EXPTIMEHIGH},
+ {0xa0, 0x91, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+ {0xaa, 0x12, 0x0069},
+ {0xaa, 0x04, 0x0020},
+ {0xaa, 0x06, 0x0050},
+ {0xaa, 0x13, 0x0083},
+ {0xaa, 0x14, 0x0000},
+ {0xaa, 0x15, 0x0024},
+ {0xaa, 0x17, 0x0018},
+ {0xaa, 0x18, 0x00ba},
+ {0xaa, 0x19, 0x0002},
+ {0xaa, 0x1a, 0x00f6},
+ {0xaa, 0x1b, 0x0002},
+ {0xaa, 0x20, 0x00c2},
+ {0xaa, 0x24, 0x0060},
+ {0xaa, 0x25, 0x0040},
+ {0xaa, 0x26, 0x0030},
+ {0xaa, 0x27, 0x00ea},
+ {0xaa, 0x28, 0x00a0},
+ {0xaa, 0x21, 0x0000},
+ {0xaa, 0x2a, 0x0081},
+ {0xaa, 0x2b, 0x0096},
+ {0xaa, 0x2d, 0x0094},
+ {0xaa, 0x2f, 0x003d},
+ {0xaa, 0x30, 0x0024},
+ {0xaa, 0x60, 0x0000},
+ {0xaa, 0x61, 0x0040},
+ {0xaa, 0x68, 0x007c},
+ {0xaa, 0x6f, 0x0015},
+ {0xaa, 0x75, 0x0088},
+ {0xaa, 0x77, 0x00b5},
+ {0xaa, 0x01, 0x0060},
+ {0xaa, 0x02, 0x0060},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x60, ZC3XX_R116_RGAIN},
+ {0xa0, 0x46, ZC3XX_R118_BGAIN},
+ {0xa0, 0x04, ZC3XX_R113_RGB03},
+/* 0x10, */
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf8, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf8, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf8, ZC3XX_R10D_RGB10},
+ {0xa0, 0x50, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf8, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf8, ZC3XX_R110_RGB20},
+ {0xa0, 0xf8, ZC3XX_R111_RGB21},
+ {0xa0, 0x50, ZC3XX_R112_RGB22},
+/* 0x03, */
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x01, ZC3XX_R120_GAMMA00}, /* gamma 2 ?*/
+ {0xa0, 0x0c, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x1f, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x3a, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x53, ZC3XX_R124_GAMMA04},
+ {0xa0, 0x6d, ZC3XX_R125_GAMMA05},
+ {0xa0, 0x85, ZC3XX_R126_GAMMA06},
+ {0xa0, 0x9c, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xb0, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xc2, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xd1, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xde, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xe9, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xf2, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xf9, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x05, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x0f, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x16, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1a, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x19, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x19, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x17, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x15, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x12, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x10, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x0e, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x0b, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x09, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x08, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x06, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x03, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf8, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf8, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf8, ZC3XX_R10D_RGB10},
+ {0xa0, 0x50, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf8, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf8, ZC3XX_R110_RGB20},
+ {0xa0, 0xf8, ZC3XX_R111_RGB21},
+ {0xa0, 0x50, ZC3XX_R112_RGB22},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xaa, 0x10, 0x001b},
+ {0xaa, 0x76, 0x0002},
+ {0xaa, 0x2a, 0x0081},
+ {0xaa, 0x2b, 0x0000},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xb8, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x37, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xaa, 0x13, 0x0083}, /* 40 */
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+
+static const struct usb_action ov7630c_InitialScale[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+
+ {0xaa, 0x12, 0x0080},
+ {0xa0, 0x02, ZC3XX_R083_RGAINADDR},
+ {0xa0, 0x01, ZC3XX_R085_BGAINADDR},
+ {0xa0, 0x90, ZC3XX_R086_EXPTIMEHIGH},
+ {0xa0, 0x91, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},
+ {0xaa, 0x12, 0x0069}, /* i2c */
+ {0xaa, 0x04, 0x0020},
+ {0xaa, 0x06, 0x0050},
+ {0xaa, 0x13, 0x00c3},
+ {0xaa, 0x14, 0x0000},
+ {0xaa, 0x15, 0x0024},
+ {0xaa, 0x19, 0x0003},
+ {0xaa, 0x1a, 0x00f6},
+ {0xaa, 0x1b, 0x0002},
+ {0xaa, 0x20, 0x00c2},
+ {0xaa, 0x24, 0x0060},
+ {0xaa, 0x25, 0x0040},
+ {0xaa, 0x26, 0x0030},
+ {0xaa, 0x27, 0x00ea},
+ {0xaa, 0x28, 0x00a0},
+ {0xaa, 0x21, 0x0000},
+ {0xaa, 0x2a, 0x0081},
+ {0xaa, 0x2b, 0x0096},
+ {0xaa, 0x2d, 0x0084},
+ {0xaa, 0x2f, 0x003d},
+ {0xaa, 0x30, 0x0024},
+ {0xaa, 0x60, 0x0000},
+ {0xaa, 0x61, 0x0040},
+ {0xaa, 0x68, 0x007c},
+ {0xaa, 0x6f, 0x0015},
+ {0xaa, 0x75, 0x0088},
+ {0xaa, 0x77, 0x00b5},
+ {0xaa, 0x01, 0x0060},
+ {0xaa, 0x02, 0x0060},
+ {0xaa, 0x17, 0x0018},
+ {0xaa, 0x18, 0x00ba},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x60, ZC3XX_R116_RGAIN},
+ {0xa0, 0x46, ZC3XX_R118_BGAIN},
+ {0xa0, 0x04, ZC3XX_R113_RGB03},
+
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x4e, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xfe, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf4, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf7, ZC3XX_R10D_RGB10},
+ {0xa0, 0x4d, ZC3XX_R10E_RGB11},
+ {0xa0, 0xfc, ZC3XX_R10F_RGB12},
+ {0xa0, 0x00, ZC3XX_R110_RGB20},
+ {0xa0, 0xf6, ZC3XX_R111_RGB21},
+ {0xa0, 0x4a, ZC3XX_R112_RGB22},
+
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x16, ZC3XX_R120_GAMMA00}, /* gamma ~4 */
+ {0xa0, 0x3a, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x5b, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x7c, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x94, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xa9, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xbb, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xca, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xd7, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xe1, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xea, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xf1, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xf7, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xfc, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x20, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x22, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x01, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x4e, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xfe, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf4, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf7, ZC3XX_R10D_RGB10},
+ {0xa0, 0x4d, ZC3XX_R10E_RGB11},
+ {0xa0, 0xfc, ZC3XX_R10F_RGB12},
+ {0xa0, 0x00, ZC3XX_R110_RGB20},
+ {0xa0, 0xf6, ZC3XX_R111_RGB21},
+ {0xa0, 0x4a, ZC3XX_R112_RGB22},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xaa, 0x10, 0x000d},
+ {0xaa, 0x76, 0x0002},
+ {0xaa, 0x2a, 0x0081},
+ {0xaa, 0x2b, 0x0000},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xd8, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x1b, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xaa, 0x13, 0x00c3},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+
+static const struct usb_action pas106b_Initial_com[] = {
+/* Sream and Sensor specific */
+ {0xa1, 0x01, 0x0010}, /* CMOSSensorSelect */
+/* System */
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* SystemControl */
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* SystemControl */
+/* Picture size */
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* ClockSelect */
+ {0xa0, 0x03, 0x003a},
+ {0xa0, 0x0c, 0x003b},
+ {0xa0, 0x04, 0x0038},
+ {}
+};
+
+static const struct usb_action pas106b_Initial[] = { /* 176x144 */
+/* JPEG control */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */
+/* Sream and Sensor specific */
+ {0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT}, /* CMOSSensorSelect */
+/* Picture size */
+ {0xa0, 0x00, ZC3XX_R003_FRAMEWIDTHHIGH}, /* FrameWidthHigh 00 */
+ {0xa0, 0xb0, ZC3XX_R004_FRAMEWIDTHLOW}, /* FrameWidthLow B0 */
+ {0xa0, 0x00, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* FrameHeightHigh 00 */
+ {0xa0, 0x90, ZC3XX_R006_FRAMEHEIGHTLOW}, /* FrameHightLow 90 */
+/* System */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* SystemOperating */
+/* Sream and Sensor specific */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */
+/* Sensor Interface */
+ {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* Compatibily Mode */
+/* Window inside sensor array */
+ {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, /* WinXStartLow */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* FirstYLow */
+ {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, /* FirstxLow */
+ {0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW}, /* WinHeightLow */
+ {0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW}, /* WinWidthLow */
+/* Init the sensor */
+ {0xaa, 0x02, 0x0004},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x09, 0x0005},
+ {0xaa, 0x0a, 0x0002},
+ {0xaa, 0x0b, 0x0002},
+ {0xaa, 0x0c, 0x0005},
+ {0xaa, 0x0d, 0x0000},
+ {0xaa, 0x0e, 0x0002},
+ {0xaa, 0x14, 0x0081},
+
+/* Other registors */
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* SensorCorrection */
+/* Frame retreiving */
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* AutoAdjustFPS */
+/* Gains */
+ {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, /* DigitalGain */
+/* Unknown */
+ {0xa0, 0x00, 0x01ad},
+/* Sharpness */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* SharpnessMode */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* Sharpness05 */
+/* Other registors */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* OperationMode */
+/* Auto exposure and white balance */
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* AWBStatus */
+/*Dead pixels */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */
+/* EEPROM */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* EEPROMAccess */
+/* JPEG control */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+/* Other registers */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* OperationMode */
+/* Auto exposure and white balance */
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* AWBStatus */
+/*Dead pixels */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */
+/* EEPROM */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* EEPROMAccess */
+/* JPEG control */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+
+ {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf4, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf4, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf4, ZC3XX_R10D_RGB10},
+ {0xa0, 0x58, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf4, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf4, ZC3XX_R110_RGB20},
+ {0xa0, 0xf4, ZC3XX_R111_RGB21},
+ {0xa0, 0x58, ZC3XX_R112_RGB22},
+/* Auto correction */
+ {0xa0, 0x03, ZC3XX_R181_WINXSTART}, /* WinXstart */
+ {0xa0, 0x08, ZC3XX_R182_WINXWIDTH}, /* WinXWidth */
+ {0xa0, 0x16, ZC3XX_R183_WINXCENTER}, /* WinXCenter */
+ {0xa0, 0x03, ZC3XX_R184_WINYSTART}, /* WinYStart */
+ {0xa0, 0x05, ZC3XX_R185_WINYWIDTH}, /* WinYWidth */
+ {0xa0, 0x14, ZC3XX_R186_WINYCENTER}, /* WinYCenter */
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */
+
+/* Auto exposure and white balance */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* ExposureLimitHigh */
+ {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* ExposureLimitMid */
+ {0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW}, /* ExposureLimitLow */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* AntiFlickerHigh */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* AntiFlickerLow */
+ {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, /* AntiFlickerLow */
+ {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* AEBFreeze */
+ {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* AEBUnfreeze */
+/* sensor on */
+ {0xaa, 0x07, 0x00b1},
+ {0xaa, 0x05, 0x0003},
+ {0xaa, 0x04, 0x0001},
+ {0xaa, 0x03, 0x003b},
+/* Gains */
+ {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* DigitalLimitDiff */
+ {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* DigitalGainStep */
+ {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, /* GlobalGain */
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* GlobalGain */
+/* Auto correction */
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */
+ {0xa1, 0x01, 0x0180}, /* AutoCorrectEnable */
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */
+/* Gains */
+ {0xa0, 0x40, ZC3XX_R116_RGAIN}, /* RGain */
+ {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* GGain */
+ {0xa0, 0x40, ZC3XX_R118_BGAIN}, /* BGain */
+ {}
+};
+
+static const struct usb_action pas106b_InitialScale[] = { /* 352x288 */
+/* JPEG control */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */
+/* Sream and Sensor specific */
+ {0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT}, /* CMOSSensorSelect */
+/* Picture size */
+ {0xa0, 0x01, ZC3XX_R003_FRAMEWIDTHHIGH}, /* FrameWidthHigh */
+ {0xa0, 0x60, ZC3XX_R004_FRAMEWIDTHLOW}, /* FrameWidthLow */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* FrameHeightHigh */
+ {0xa0, 0x20, ZC3XX_R006_FRAMEHEIGHTLOW}, /* FrameHightLow */
+/* System */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* SystemOperating */
+/* Sream and Sensor specific */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */
+/* Sensor Interface */
+ {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* Compatibily Mode */
+/* Window inside sensor array */
+ {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, /* WinXStartLow */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* FirstYLow */
+ {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, /* FirstxLow */
+ {0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW}, /* WinHeightLow */
+ {0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW}, /* WinWidthLow */
+/* Init the sensor */
+ {0xaa, 0x02, 0x0004},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x09, 0x0005},
+ {0xaa, 0x0a, 0x0002},
+ {0xaa, 0x0b, 0x0002},
+ {0xaa, 0x0c, 0x0005},
+ {0xaa, 0x0d, 0x0000},
+ {0xaa, 0x0e, 0x0002},
+ {0xaa, 0x14, 0x0081},
+
+/* Other registors */
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* SensorCorrection */
+/* Frame retreiving */
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* AutoAdjustFPS */
+/* Gains */
+ {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, /* DigitalGain */
+/* Unknown */
+ {0xa0, 0x00, 0x01ad},
+/* Sharpness */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* SharpnessMode */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* Sharpness05 */
+/* Other registors */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* OperationMode */
+/* Auto exposure and white balance */
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* AWBStatus */
+ {0xa0, 0x80, ZC3XX_R18D_YTARGET}, /* ????????? */
+/*Dead pixels */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */
+/* EEPROM */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* EEPROMAccess */
+/* JPEG control */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+/* Other registers */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* OperationMode */
+/* Auto exposure and white balance */
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* AWBStatus */
+/*Dead pixels */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */
+/* EEPROM */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* EEPROMAccess */
+/* JPEG control */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+
+ {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf4, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf4, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf4, ZC3XX_R10D_RGB10},
+ {0xa0, 0x58, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf4, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf4, ZC3XX_R110_RGB20},
+ {0xa0, 0xf4, ZC3XX_R111_RGB21},
+ {0xa0, 0x58, ZC3XX_R112_RGB22},
+/* Auto correction */
+ {0xa0, 0x03, ZC3XX_R181_WINXSTART}, /* WinXstart */
+ {0xa0, 0x08, ZC3XX_R182_WINXWIDTH}, /* WinXWidth */
+ {0xa0, 0x16, ZC3XX_R183_WINXCENTER}, /* WinXCenter */
+ {0xa0, 0x03, ZC3XX_R184_WINYSTART}, /* WinYStart */
+ {0xa0, 0x05, ZC3XX_R185_WINYWIDTH}, /* WinYWidth */
+ {0xa0, 0x14, ZC3XX_R186_WINYCENTER}, /* WinYCenter */
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */
+
+/* Auto exposure and white balance */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* ExposureLimitHigh 0 */
+ {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* ExposureLimitMid */
+ {0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW}, /* ExposureLimitLow 0xb1 */
+
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* AntiFlickerHigh 0x00 */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* AntiFlickerLow 0x00 */
+ {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, /* AntiFlickerLow 0x87 */
+
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* AEBFreeze 0x10 0x0c */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* AEBUnfreeze 0x30 0x18 */
+/* sensor on */
+ {0xaa, 0x07, 0x00b1},
+ {0xaa, 0x05, 0x0003},
+ {0xaa, 0x04, 0x0001},
+ {0xaa, 0x03, 0x003b},
+/* Gains */
+ {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* DigitalLimitDiff */
+ {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* DigitalGainStep */
+ {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, /* GlobalGain */
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* GlobalGain */
+/* Auto correction */
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */
+ {0xa1, 0x01, 0x0180}, /* AutoCorrectEnable */
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */
+/* Gains */
+ {0xa0, 0x40, ZC3XX_R116_RGAIN}, /* RGain */
+ {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* GGain */
+ {0xa0, 0x40, ZC3XX_R118_BGAIN}, /* BGain */
+
+ {0xa0, 0x00, 0x0007}, /* AutoCorrectEnable */
+ {0xa0, 0xff, ZC3XX_R018_FRAMELOST}, /* Frame adjust */
+ {}
+};
+static const struct usb_action pas106b_50HZ[] = {
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */
+ {0xa0, 0x54, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,54,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,87,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x30, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,30,cc */
+ {0xaa, 0x03, 0x0021}, /* 00,03,21,aa */
+ {0xaa, 0x04, 0x000c}, /* 00,04,0c,aa */
+ {0xaa, 0x05, 0x0002}, /* 00,05,02,aa */
+ {0xaa, 0x07, 0x001c}, /* 00,07,1c,aa */
+ {0xa0, 0x04, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,04,cc */
+ {}
+};
+static const struct usb_action pas106b_60HZ[] = {
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */
+ {0xa0, 0x2e, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,2e,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x71, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,71,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x30, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,30,cc */
+ {0xaa, 0x03, 0x001c}, /* 00,03,1c,aa */
+ {0xaa, 0x04, 0x0004}, /* 00,04,04,aa */
+ {0xaa, 0x05, 0x0001}, /* 00,05,01,aa */
+ {0xaa, 0x07, 0x00c4}, /* 00,07,c4,aa */
+ {0xa0, 0x04, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,04,cc */
+ {}
+};
+static const struct usb_action pas106b_NoFliker[] = {
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */
+ {0xa0, 0x50, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xaa, 0x03, 0x0013}, /* 00,03,13,aa */
+ {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */
+ {0xaa, 0x05, 0x0001}, /* 00,05,01,aa */
+ {0xaa, 0x07, 0x0030}, /* 00,07,30,aa */
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+ {}
+};
+
+static const struct usb_action pb03303x_Initial[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, /* 8b -> dc */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xaa, 0x01, 0x0001},
+ {0xaa, 0x06, 0x0000},
+ {0xaa, 0x08, 0x0483},
+ {0xaa, 0x01, 0x0004},
+ {0xaa, 0x08, 0x0006},
+ {0xaa, 0x02, 0x0011},
+ {0xaa, 0x03, 0x01e7},
+ {0xaa, 0x04, 0x0287},
+ {0xaa, 0x07, 0x3002},
+ {0xaa, 0x20, 0x1100},
+ {0xaa, 0x35, 0x0050},
+ {0xaa, 0x30, 0x0005},
+ {0xaa, 0x31, 0x0000},
+ {0xaa, 0x58, 0x0078},
+ {0xaa, 0x62, 0x0411},
+ {0xaa, 0x2b, 0x0028},
+ {0xaa, 0x2c, 0x0030},
+ {0xaa, 0x2d, 0x0030},
+ {0xaa, 0x2e, 0x0028},
+ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x78, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x61, ZC3XX_R116_RGAIN},
+ {0xa0, 0x65, ZC3XX_R118_BGAIN},
+
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x0d, 0x003a},
+ {0xa0, 0x02, 0x003b},
+ {0xa0, 0x00, 0x0038},
+ {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf8, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf8, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf8, ZC3XX_R10D_RGB10},
+ {0xa0, 0x50, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf8, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf8, ZC3XX_R110_RGB20},
+ {0xa0, 0xf8, ZC3XX_R111_RGB21},
+ {0xa0, 0x50, ZC3XX_R112_RGB22},
+
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */
+ {0xa0, 0x38, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x59, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x79, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x92, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x26, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x22, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf8, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf8, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf8, ZC3XX_R10D_RGB10},
+ {0xa0, 0x50, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf8, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf8, ZC3XX_R110_RGB20},
+ {0xa0, 0xf8, ZC3XX_R111_RGB21},
+ {0xa0, 0x50, ZC3XX_R112_RGB22},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x05, 0x0009},
+ {0xaa, 0x09, 0x0134},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xec, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x9c, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+
+static const struct usb_action pb03303x_InitialScale[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, /* 8b -> dc */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xaa, 0x01, 0x0001},
+ {0xaa, 0x06, 0x0000},
+ {0xaa, 0x08, 0x0483},
+ {0xaa, 0x01, 0x0004},
+ {0xaa, 0x08, 0x0006},
+ {0xaa, 0x02, 0x0011},
+ {0xaa, 0x03, 0x01e7},
+ {0xaa, 0x04, 0x0287},
+ {0xaa, 0x07, 0x3002},
+ {0xaa, 0x20, 0x1100},
+ {0xaa, 0x35, 0x0050},
+ {0xaa, 0x30, 0x0005},
+ {0xaa, 0x31, 0x0000},
+ {0xaa, 0x58, 0x0078},
+ {0xaa, 0x62, 0x0411},
+ {0xaa, 0x2b, 0x0028},
+ {0xaa, 0x2c, 0x0030},
+ {0xaa, 0x2d, 0x0030},
+ {0xaa, 0x2e, 0x0028},
+ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x78, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x61, ZC3XX_R116_RGAIN},
+ {0xa0, 0x65, ZC3XX_R118_BGAIN},
+
+ {0xa1, 0x01, 0x0002},
+
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+
+ {0xa0, 0x0d, 0x003a},
+ {0xa0, 0x02, 0x003b},
+ {0xa0, 0x00, 0x0038},
+ {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf8, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf8, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf8, ZC3XX_R10D_RGB10},
+ {0xa0, 0x50, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf8, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf8, ZC3XX_R110_RGB20},
+ {0xa0, 0xf8, ZC3XX_R111_RGB21},
+ {0xa0, 0x50, ZC3XX_R112_RGB22},
+
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+
+ {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */
+ {0xa0, 0x38, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x59, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x79, ZC3XX_R123_GAMMA03},
+ {0xa0, 0x92, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x26, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x22, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf8, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf8, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf8, ZC3XX_R10D_RGB10},
+ {0xa0, 0x50, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf8, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf8, ZC3XX_R110_RGB20},
+ {0xa0, 0xf8, ZC3XX_R111_RGB21},
+ {0xa0, 0x50, ZC3XX_R112_RGB22},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x05, 0x0009},
+ {0xaa, 0x09, 0x0134},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xec, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x9c, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+static const struct usb_action pb0330xx_Initial[] = {
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */
+ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xaa, 0x01, 0x0006},
+ {0xaa, 0x02, 0x0011},
+ {0xaa, 0x03, 0x01e7},
+ {0xaa, 0x04, 0x0287},
+ {0xaa, 0x06, 0x0003},
+ {0xaa, 0x07, 0x3002},
+ {0xaa, 0x20, 0x1100},
+ {0xaa, 0x2f, 0xf7b0},
+ {0xaa, 0x30, 0x0005},
+ {0xaa, 0x31, 0x0000},
+ {0xaa, 0x34, 0x0100},
+ {0xaa, 0x35, 0x0060},
+ {0xaa, 0x3d, 0x068f},
+ {0xaa, 0x40, 0x01e0},
+ {0xaa, 0x58, 0x0078},
+ {0xaa, 0x62, 0x0411},
+ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x6c, ZC3XX_R18D_YTARGET},
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
+ {0xa1, 0x01, 0x0091},
+ {0xa1, 0x01, 0x0095},
+ {0xa1, 0x01, 0x0096},
+ {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf8, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf8, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf8, ZC3XX_R10D_RGB10},
+ {0xa0, 0x50, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf8, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf8, ZC3XX_R110_RGB20},
+ {0xa0, 0xf8, ZC3XX_R111_RGB21},
+ {0xa0, 0x50, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+
+ {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf8, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf8, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf8, ZC3XX_R10D_RGB10},
+ {0xa0, 0x50, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf8, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf8, ZC3XX_R110_RGB20},
+ {0xa0, 0xf8, ZC3XX_R111_RGB21},
+ {0xa0, 0x50, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x05, 0x0066},
+ {0xaa, 0x09, 0x02b2},
+ {0xaa, 0x10, 0x0002},
+
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x8c, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x8a, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xf0, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0007},
+/* {0xa0, 0x30, 0x0007}, */
+/* {0xa0, 0x00, 0x0007}, */
+ {}
+};
+
+static const struct usb_action pb0330xx_InitialScale[] = {
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */
+ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 10 */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xaa, 0x01, 0x0006},
+ {0xaa, 0x02, 0x0011},
+ {0xaa, 0x03, 0x01e7},
+ {0xaa, 0x04, 0x0287},
+ {0xaa, 0x06, 0x0003},
+ {0xaa, 0x07, 0x3002},
+ {0xaa, 0x20, 0x1100},
+ {0xaa, 0x2f, 0xf7b0},
+ {0xaa, 0x30, 0x0005},
+ {0xaa, 0x31, 0x0000},
+ {0xaa, 0x34, 0x0100},
+ {0xaa, 0x35, 0x0060},
+ {0xaa, 0x3d, 0x068f},
+ {0xaa, 0x40, 0x01e0},
+ {0xaa, 0x58, 0x0078},
+ {0xaa, 0x62, 0x0411},
+ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x6c, ZC3XX_R18D_YTARGET},
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
+ {0xa1, 0x01, 0x0091},
+ {0xa1, 0x01, 0x0095},
+ {0xa1, 0x01, 0x0096},
+ {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf8, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf8, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf8, ZC3XX_R10D_RGB10},
+ {0xa0, 0x50, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf8, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf8, ZC3XX_R110_RGB20},
+ {0xa0, 0xf8, ZC3XX_R111_RGB21},
+ {0xa0, 0x50, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+
+ {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf8, ZC3XX_R10B_RGB01},
+ {0xa0, 0xf8, ZC3XX_R10C_RGB02},
+ {0xa0, 0xf8, ZC3XX_R10D_RGB10},
+ {0xa0, 0x50, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf8, ZC3XX_R10F_RGB12},
+ {0xa0, 0xf8, ZC3XX_R110_RGB20},
+ {0xa0, 0xf8, ZC3XX_R111_RGB21},
+ {0xa0, 0x50, ZC3XX_R112_RGB22},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x05, 0x0066},
+ {0xaa, 0x09, 0x02b2},
+ {0xaa, 0x10, 0x0002},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x8c, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x8a, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xf0, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0007},
+/* {0xa0, 0x30, 0x0007}, */
+/* {0xa0, 0x00, 0x0007}, */
+ {}
+};
+static const struct usb_action pb0330_50HZ[] = {
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+ {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,ee,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x46, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,46,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+ {0xa0, 0x68, ZC3XX_R01D_HSYNC_0}, /* 00,1d,68,cc */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */
+ {}
+};
+static const struct usb_action pb0330_50HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+ {0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,a0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x7a, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7a,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+ {0xa0, 0xe5, ZC3XX_R01D_HSYNC_0}, /* 00,1d,e5,cc */
+ {0xa0, 0xf0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,f0,cc */
+ {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f8,cc */
+ {}
+};
+static const struct usb_action pb0330_60HZ[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+ {0xa0, 0xdd, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,dd,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3d,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+ {0xa0, 0x43, ZC3XX_R01D_HSYNC_0}, /* 00,1d,43,cc */
+ {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */
+ {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
+ {}
+};
+static const struct usb_action pb0330_60HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+ {0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,a0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x7a, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7a,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+ {0xa0, 0x41, ZC3XX_R01D_HSYNC_0}, /* 00,1d,41,cc */
+ {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */
+ {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
+ {}
+};
+static const struct usb_action pb0330_NoFliker[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+ {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0x09, ZC3XX_R01D_HSYNC_0}, /* 00,1d,09,cc */
+ {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, /* 00,1e,40,cc */
+ {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
+ {}
+};
+static const struct usb_action pb0330_NoFlikerScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+ {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0x09, ZC3XX_R01D_HSYNC_0}, /* 00,1d,09,cc */
+ {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, /* 00,1e,40,cc */
+ {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
+ {}
+};
+
+/* from oem9.inf - HKR,%PO2030%,Initial - 640x480 - (close to CS2102) */
+static const struct usb_action PO2030_mode0[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+ {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT}, /* 00,02,04,cc */
+ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+ {0xa0, 0x04, ZC3XX_R080_HBLANKHIGH}, /* 00,80,04,cc */
+ {0xa0, 0x05, ZC3XX_R081_HBLANKLOW}, /* 00,81,05,cc */
+ {0xa0, 0x16, ZC3XX_R083_RGAINADDR}, /* 00,83,16,cc */
+ {0xa0, 0x18, ZC3XX_R085_BGAINADDR}, /* 00,85,18,cc */
+ {0xa0, 0x1a, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,1a,cc */
+ {0xa0, 0x1b, ZC3XX_R087_EXPTIMEMID}, /* 00,87,1b,cc */
+ {0xa0, 0x1c, ZC3XX_R088_EXPTIMELOW}, /* 00,88,1c,cc */
+ {0xa0, 0xee, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,ee,cc */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */
+ {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
+ {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc */
+ {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */
+ {0xaa, 0x09, 0x00ce}, /* 00,09,ce,aa */
+ {0xaa, 0x0b, 0x0005}, /* 00,0b,05,aa */
+ {0xaa, 0x0d, 0x0054}, /* 00,0d,54,aa */
+ {0xaa, 0x0f, 0x00eb}, /* 00,0f,eb,aa */
+ {0xaa, 0x87, 0x0000}, /* 00,87,00,aa */
+ {0xaa, 0x88, 0x0004}, /* 00,88,04,aa */
+ {0xaa, 0x89, 0x0000}, /* 00,89,00,aa */
+ {0xaa, 0x8a, 0x0005}, /* 00,8a,05,aa */
+ {0xaa, 0x13, 0x0003}, /* 00,13,03,aa */
+ {0xaa, 0x16, 0x0040}, /* 00,16,40,aa */
+ {0xaa, 0x18, 0x0040}, /* 00,18,40,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x29, 0x00e8}, /* 00,29,e8,aa */
+ {0xaa, 0x45, 0x0045}, /* 00,45,45,aa */
+ {0xaa, 0x50, 0x00ed}, /* 00,50,ed,aa */
+ {0xaa, 0x51, 0x0025}, /* 00,51,25,aa */
+ {0xaa, 0x52, 0x0042}, /* 00,52,42,aa */
+ {0xaa, 0x53, 0x002f}, /* 00,53,2f,aa */
+ {0xaa, 0x79, 0x0025}, /* 00,79,25,aa */
+ {0xaa, 0x7b, 0x0000}, /* 00,7b,00,aa */
+ {0xaa, 0x7e, 0x0025}, /* 00,7e,25,aa */
+ {0xaa, 0x7f, 0x0025}, /* 00,7f,25,aa */
+ {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+ {0xaa, 0x33, 0x0036}, /* 00,33,36,aa */
+ {0xaa, 0x36, 0x0060}, /* 00,36,60,aa */
+ {0xaa, 0x37, 0x0008}, /* 00,37,08,aa */
+ {0xaa, 0x3b, 0x0031}, /* 00,3b,31,aa */
+ {0xaa, 0x44, 0x000f}, /* 00,44,0f,aa */
+ {0xaa, 0x58, 0x0002}, /* 00,58,02,aa */
+ {0xaa, 0x66, 0x00c0}, /* 00,66,c0,aa */
+ {0xaa, 0x67, 0x0044}, /* 00,67,44,aa */
+ {0xaa, 0x6b, 0x00a0}, /* 00,6b,a0,aa */
+ {0xaa, 0x6c, 0x0054}, /* 00,6c,54,aa */
+ {0xaa, 0xd6, 0x0007}, /* 00,d6,07,aa */
+ {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,f7,cc */
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+ {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+ {0xa0, 0x7a, ZC3XX_R116_RGAIN}, /* 01,16,7a,cc */
+ {0xa0, 0x4a, ZC3XX_R118_BGAIN}, /* 01,18,4a,cc */
+ {}
+};
+
+/* from oem9.inf - HKR,%PO2030%,InitialScale - 320x240 */
+static const struct usb_action PO2030_mode1[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */
+ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+ {0xa0, 0x04, ZC3XX_R080_HBLANKHIGH}, /* 00,80,04,cc */
+ {0xa0, 0x05, ZC3XX_R081_HBLANKLOW}, /* 00,81,05,cc */
+ {0xa0, 0x16, ZC3XX_R083_RGAINADDR}, /* 00,83,16,cc */
+ {0xa0, 0x18, ZC3XX_R085_BGAINADDR}, /* 00,85,18,cc */
+ {0xa0, 0x1a, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,1a,cc */
+ {0xa0, 0x1b, ZC3XX_R087_EXPTIMEMID}, /* 00,87,1b,cc */
+ {0xa0, 0x1c, ZC3XX_R088_EXPTIMELOW}, /* 00,88,1c,cc */
+ {0xa0, 0xee, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,ee,cc */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */
+ {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc */
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */
+ {0xaa, 0x09, 0x00cc}, /* 00,09,cc,aa */
+ {0xaa, 0x0b, 0x0005}, /* 00,0b,05,aa */
+ {0xaa, 0x0d, 0x0058}, /* 00,0d,58,aa */
+ {0xaa, 0x0f, 0x00ed}, /* 00,0f,ed,aa */
+ {0xaa, 0x87, 0x0000}, /* 00,87,00,aa */
+ {0xaa, 0x88, 0x0004}, /* 00,88,04,aa */
+ {0xaa, 0x89, 0x0000}, /* 00,89,00,aa */
+ {0xaa, 0x8a, 0x0005}, /* 00,8a,05,aa */
+ {0xaa, 0x13, 0x0003}, /* 00,13,03,aa */
+ {0xaa, 0x16, 0x0040}, /* 00,16,40,aa */
+ {0xaa, 0x18, 0x0040}, /* 00,18,40,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x29, 0x00e8}, /* 00,29,e8,aa */
+ {0xaa, 0x45, 0x0045}, /* 00,45,45,aa */
+ {0xaa, 0x50, 0x00ed}, /* 00,50,ed,aa */
+ {0xaa, 0x51, 0x0025}, /* 00,51,25,aa */
+ {0xaa, 0x52, 0x0042}, /* 00,52,42,aa */
+ {0xaa, 0x53, 0x002f}, /* 00,53,2f,aa */
+ {0xaa, 0x79, 0x0025}, /* 00,79,25,aa */
+ {0xaa, 0x7b, 0x0000}, /* 00,7b,00,aa */
+ {0xaa, 0x7e, 0x0025}, /* 00,7e,25,aa */
+ {0xaa, 0x7f, 0x0025}, /* 00,7f,25,aa */
+ {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+ {0xaa, 0x33, 0x0036}, /* 00,33,36,aa */
+ {0xaa, 0x36, 0x0060}, /* 00,36,60,aa */
+ {0xaa, 0x37, 0x0008}, /* 00,37,08,aa */
+ {0xaa, 0x3b, 0x0031}, /* 00,3b,31,aa */
+ {0xaa, 0x44, 0x000f}, /* 00,44,0f,aa */
+ {0xaa, 0x58, 0x0002}, /* 00,58,02,aa */
+ {0xaa, 0x66, 0x00c0}, /* 00,66,c0,aa */
+ {0xaa, 0x67, 0x0044}, /* 00,67,44,aa */
+ {0xaa, 0x6b, 0x00a0}, /* 00,6b,a0,aa */
+ {0xaa, 0x6c, 0x0054}, /* 00,6c,54,aa */
+ {0xaa, 0xd6, 0x0007}, /* 00,d6,07,aa */
+ {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,f7,cc */
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+ {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+ {0xa0, 0x7a, ZC3XX_R116_RGAIN}, /* 01,16,7a,cc */
+ {0xa0, 0x4a, ZC3XX_R118_BGAIN}, /* 01,18,4a,cc */
+ {}
+};
+
+static const struct usb_action PO2030_50HZ[] = {
+ {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */
+ {0xaa, 0x1a, 0x0001}, /* 00,1a,01,aa */
+ {0xaa, 0x1b, 0x000a}, /* 00,1b,0a,aa */
+ {0xaa, 0x1c, 0x00b0}, /* 00,1c,b0,aa */
+ {0xa0, 0x05, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,05,cc */
+ {0xa0, 0x35, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,35,cc */
+ {0xa0, 0x70, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,70,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x85, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,85,cc */
+ {0xa0, 0x58, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,58,cc */
+ {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */
+ {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+ {0xa0, 0x22, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,22,cc */
+ {0xa0, 0x88, ZC3XX_R18D_YTARGET}, /* 01,8d,88,cc */
+ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc */
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */
+ {}
+};
+
+static const struct usb_action PO2030_60HZ[] = {
+ {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */
+ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */
+ {0xaa, 0x1b, 0x00de}, /* 00,1b,de,aa */
+ {0xaa, 0x1c, 0x0040}, /* 00,1c,40,aa */
+ {0xa0, 0x08, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,08,cc */
+ {0xa0, 0xae, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,ae,cc */
+ {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x6f, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,6f,cc */
+ {0xa0, 0x20, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,20,cc */
+ {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */
+ {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+ {0xa0, 0x22, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,22,cc */
+ {0xa0, 0x88, ZC3XX_R18D_YTARGET}, /* 01,8d,88,cc */
+ /* win: 01,8d,80 */
+ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc */
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */
+ {}
+};
+
+static const struct usb_action PO2030_NoFliker[] = {
+ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
+ {0xaa, 0x8d, 0x000d}, /* 00,8d,0d,aa */
+ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */
+ {0xaa, 0x1b, 0x0002}, /* 00,1b,02,aa */
+ {0xaa, 0x1c, 0x0078}, /* 00,1c,78,aa */
+ {0xaa, 0x46, 0x0000}, /* 00,46,00,aa */
+ {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */
+ {}
+};
+
+/* TEST */
+static const struct usb_action tas5130CK_Initial[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x01, 0x003b},
+ {0xa0, 0x0e, 0x003a},
+ {0xa0, 0x01, 0x0038},
+ {0xa0, 0x0b, 0x0039},
+ {0xa0, 0x00, 0x0038},
+ {0xa0, 0x0b, 0x0039},
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x83, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x04, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x06, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x02, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x11, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0xE7, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x01, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x87, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x02, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x07, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x30, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x51, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x35, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7F, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x30, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x05, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x31, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x58, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x78, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x62, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x11, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x04, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x2B, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x2c, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x2D, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x2e, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x6c, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x61, ZC3XX_R116_RGAIN},
+ {0xa0, 0x65, ZC3XX_R118_BGAIN},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf1, ZC3XX_R10B_RGB01},
+ {0xa0, 0x03, ZC3XX_R10C_RGB02},
+ {0xa0, 0xfe, ZC3XX_R10D_RGB10},
+ {0xa0, 0x51, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf1, ZC3XX_R10F_RGB12},
+ {0xa0, 0xec, ZC3XX_R110_RGB20},
+ {0xa0, 0x03, ZC3XX_R111_RGB21},
+ {0xa0, 0x51, ZC3XX_R112_RGB22},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x38, ZC3XX_R120_GAMMA00}, /* gamma > 5 */
+ {0xa0, 0x51, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x6e, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x8c, ZC3XX_R123_GAMMA03},
+ {0xa0, 0xa2, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xb6, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xc8, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xd6, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xe2, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xed, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xf5, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xfc, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xff, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xff, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x12, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x1b, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x1d, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1a, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x15, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x12, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x0f, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x05, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x00, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x00, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x01, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf1, ZC3XX_R10B_RGB01},
+ {0xa0, 0x03, ZC3XX_R10C_RGB02},
+ {0xa0, 0xfe, ZC3XX_R10D_RGB10},
+ {0xa0, 0x51, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf1, ZC3XX_R10F_RGB12},
+ {0xa0, 0xec, ZC3XX_R110_RGB20},
+ {0xa0, 0x03, ZC3XX_R111_RGB21},
+ {0xa0, 0x51, ZC3XX_R112_RGB22},
+ {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x09, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x34, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x01, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+
+static const struct usb_action tas5130CK_InitialScale[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x01, 0x003b},
+ {0xa0, 0x0e, 0x003a},
+ {0xa0, 0x01, 0x0038},
+ {0xa0, 0x0b, 0x0039},
+ {0xa0, 0x00, 0x0038},
+ {0xa0, 0x0b, 0x0039},
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x83, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x04, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x06, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x02, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x11, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0xe5, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x01, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x85, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x02, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x07, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x30, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x51, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x35, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7F, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x50, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x30, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x05, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x31, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x58, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x78, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x62, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x11, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x04, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x2B, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x2C, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7F, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x2D, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x2e, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x6c, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x61, ZC3XX_R116_RGAIN},
+ {0xa0, 0x65, ZC3XX_R118_BGAIN},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf1, ZC3XX_R10B_RGB01},
+ {0xa0, 0x03, ZC3XX_R10C_RGB02},
+ {0xa0, 0xfe, ZC3XX_R10D_RGB10},
+ {0xa0, 0x51, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf1, ZC3XX_R10F_RGB12},
+ {0xa0, 0xec, ZC3XX_R110_RGB20},
+ {0xa0, 0x03, ZC3XX_R111_RGB21},
+ {0xa0, 0x51, ZC3XX_R112_RGB22},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+ {0xa0, 0x38, ZC3XX_R120_GAMMA00}, /* gamma > 5 */
+ {0xa0, 0x51, ZC3XX_R121_GAMMA01},
+ {0xa0, 0x6e, ZC3XX_R122_GAMMA02},
+ {0xa0, 0x8c, ZC3XX_R123_GAMMA03},
+ {0xa0, 0xa2, ZC3XX_R124_GAMMA04},
+ {0xa0, 0xb6, ZC3XX_R125_GAMMA05},
+ {0xa0, 0xc8, ZC3XX_R126_GAMMA06},
+ {0xa0, 0xd6, ZC3XX_R127_GAMMA07},
+ {0xa0, 0xe2, ZC3XX_R128_GAMMA08},
+ {0xa0, 0xed, ZC3XX_R129_GAMMA09},
+ {0xa0, 0xf5, ZC3XX_R12A_GAMMA0A},
+ {0xa0, 0xfc, ZC3XX_R12B_GAMMA0B},
+ {0xa0, 0xff, ZC3XX_R12C_GAMMA0C},
+ {0xa0, 0xff, ZC3XX_R12D_GAMMA0D},
+ {0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
+ {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+ {0xa0, 0x12, ZC3XX_R130_GAMMA10},
+ {0xa0, 0x1b, ZC3XX_R131_GAMMA11},
+ {0xa0, 0x1d, ZC3XX_R132_GAMMA12},
+ {0xa0, 0x1a, ZC3XX_R133_GAMMA13},
+ {0xa0, 0x15, ZC3XX_R134_GAMMA14},
+ {0xa0, 0x12, ZC3XX_R135_GAMMA15},
+ {0xa0, 0x0f, ZC3XX_R136_GAMMA16},
+ {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+ {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+ {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+ {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+ {0xa0, 0x05, ZC3XX_R13B_GAMMA1B},
+ {0xa0, 0x00, ZC3XX_R13C_GAMMA1C},
+ {0xa0, 0x00, ZC3XX_R13D_GAMMA1D},
+ {0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
+ {0xa0, 0x01, ZC3XX_R13F_GAMMA1F},
+ {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xf1, ZC3XX_R10B_RGB01},
+ {0xa0, 0x03, ZC3XX_R10C_RGB02},
+ {0xa0, 0xfe, ZC3XX_R10D_RGB10},
+ {0xa0, 0x51, ZC3XX_R10E_RGB11},
+ {0xa0, 0xf1, ZC3XX_R10F_RGB12},
+ {0xa0, 0xec, ZC3XX_R110_RGB20},
+ {0xa0, 0x03, ZC3XX_R111_RGB21},
+ {0xa0, 0x51, ZC3XX_R112_RGB22},
+ {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x62, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0xaa, ZC3XX_R093_I2CSETVALUE},
+ {0xa0, 0x01, ZC3XX_R094_I2CWRITEACK},
+ {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x9b, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x62, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x30, 0x0007},
+ {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x00, 0x0007},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {}
+};
+
+static const struct usb_action tas5130cxx_Initial[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x50, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN},
+ {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL},
+
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+
+ {0xa0, 0x04, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x0f, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x04, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x0f, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+ {0xa0, 0x06, ZC3XX_R08D_COMPABILITYMODE},
+ {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x68, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+
+ {0xa0, 0x68, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xec, ZC3XX_R10B_RGB01},
+ {0xa0, 0xec, ZC3XX_R10C_RGB02},
+ {0xa0, 0xec, ZC3XX_R10D_RGB10},
+ {0xa0, 0x68, ZC3XX_R10E_RGB11},
+ {0xa0, 0xec, ZC3XX_R10F_RGB12},
+ {0xa0, 0xec, ZC3XX_R110_RGB20},
+ {0xa0, 0xec, ZC3XX_R111_RGB21},
+ {0xa0, 0x68, ZC3XX_R112_RGB22},
+
+ {0xa1, 0x01, 0x018d},
+ {0xa0, 0x90, ZC3XX_R18D_YTARGET}, /* 90 */
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+
+ {0xaa, 0xa3, 0x0001},
+ {0xaa, 0xa4, 0x0077},
+ {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+ {0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW},
+
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 00 */
+ {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 03 */
+ {0xa0, 0xe8, ZC3XX_R192_EXPOSURELIMITLOW}, /* e8 */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 0 */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 0 */
+ {0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 7d */
+
+ {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 08 */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 24 */
+ {0xa0, 0xf0, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH},
+ {0xa0, 0xc0, ZC3XX_R0A0_MAXXLOW},
+ {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, /* 50 */
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+static const struct usb_action tas5130cxx_InitialScale[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT},
+
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa1, 0x01, 0x0008},
+
+ {0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN},
+ {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0x05, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x0f, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x05, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x0f, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+ {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},
+ {0xa0, 0x06, ZC3XX_R08D_COMPABILITYMODE},
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+ {0xa0, 0x68, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa1, 0x01, 0x0008}, /* clock ? */
+ {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+
+ {0xa0, 0x68, ZC3XX_R10A_RGB00}, /* matrix */
+ {0xa0, 0xec, ZC3XX_R10B_RGB01},
+ {0xa0, 0xec, ZC3XX_R10C_RGB02},
+ {0xa0, 0xec, ZC3XX_R10D_RGB10},
+ {0xa0, 0x68, ZC3XX_R10E_RGB11},
+ {0xa0, 0xec, ZC3XX_R10F_RGB12},
+ {0xa0, 0xec, ZC3XX_R110_RGB20},
+ {0xa0, 0xec, ZC3XX_R111_RGB21},
+ {0xa0, 0x68, ZC3XX_R112_RGB22},
+
+ {0xa1, 0x01, 0x018d},
+ {0xa0, 0x90, ZC3XX_R18D_YTARGET},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0xa3, 0x0001},
+ {0xaa, 0xa4, 0x0063},
+ {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+ {0xa0, 0x63, ZC3XX_R0A4_EXPOSURETIMELOW},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x38, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0xd3, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xda, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xea, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH},
+ {0xa0, 0x4c, ZC3XX_R0A0_MAXXLOW},
+ {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+static const struct usb_action tas5130cxx_50HZ[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+ {0xaa, 0xa4, 0x0063}, /* 00,a4,63,aa */
+ {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
+ {0xa0, 0x63, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,63,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */
+ {0xa0, 0x38, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,38,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+ {0xa0, 0xd3, ZC3XX_R01D_HSYNC_0}, /* 00,1d,d3,cc */
+ {0xa0, 0xda, ZC3XX_R01E_HSYNC_1}, /* 00,1e,da,cc */
+ {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */
+ {}
+};
+static const struct usb_action tas5130cxx_50HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+ {0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */
+ {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
+ {0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,77,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,03,cc */
+ {0xa0, 0xe8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,e8,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7d,cc */
+ {0xa0, 0x14, ZC3XX_R18C_AEFREEZE}, /* 01,8c,14,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+ {0xa0, 0xf0, ZC3XX_R01D_HSYNC_0}, /* 00,1d,f0,cc */
+ {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,f4,cc */
+ {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f8,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */
+ {}
+};
+static const struct usb_action tas5130cxx_60HZ[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+ {0xaa, 0xa4, 0x0036}, /* 00,a4,36,aa */
+ {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
+ {0xa0, 0x36, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,36,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,01,cc */
+ {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x3e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3e,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+ {0xa0, 0xca, ZC3XX_R01D_HSYNC_0}, /* 00,1d,ca,cc */
+ {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
+ {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */
+ {}
+};
+static const struct usb_action tas5130cxx_60HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+ {0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */
+ {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
+ {0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,77,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,03,cc */
+ {0xa0, 0xe8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,e8,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7d,cc */
+ {0xa0, 0x14, ZC3XX_R18C_AEFREEZE}, /* 01,8c,14,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+ {0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c8,cc */
+ {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
+ {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */
+ {}
+};
+static const struct usb_action tas5130cxx_NoFliker[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+ {0xaa, 0xa4, 0x0040}, /* 00,a4,40,aa */
+ {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
+ {0xa0, 0x40, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,40,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,01,cc */
+ {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0xbc, ZC3XX_R01D_HSYNC_0}, /* 00,1d,bc,cc */
+ {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
+ {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x02, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,02,cc */
+ {}
+};
+
+static const struct usb_action tas5130cxx_NoFlikerScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+ {0xaa, 0xa4, 0x0090}, /* 00,a4,90,aa */
+ {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
+ {0xa0, 0x90, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,90,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,03,cc */
+ {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0xbc, ZC3XX_R01D_HSYNC_0}, /* 00,1d,bc,cc */
+ {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
+ {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x02, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,02,cc */
+ {}
+};
+
+static const struct usb_action tas5130c_vf0250_Initial[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */
+ {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */
+ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc,
+ * 0<->10 */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc, */
+ {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc, */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc, */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc, */
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc, */
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc, */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc, */
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc, */
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc,
+ * 6<->8 */
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc,
+ * 6<->8 */
+ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */
+ {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */
+ {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */
+ {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */
+ {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */
+ {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
+ {0xaa, 0x01, 0x0000},
+ {0xaa, 0x01, 0x0000},
+ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */
+ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */
+ {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */
+ {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */
+ {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */
+ {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */
+ {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */
+ {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */
+ {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */
+ {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */
+ {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */
+ {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */
+ {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */
+ {0xa0, 0x00, 0x0039},
+ {0xa1, 0x01, 0x0037},
+ {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */
+ {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa, (e6 -> e8) */
+ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */
+ {0xaa, 0x19, 0x0088}, /* 00,19,86,aa, */
+ {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */
+ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc, */
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc, */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc, */
+ {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc, */
+ {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc, */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc, */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */
+ {0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */
+ {0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */
+ {}
+};
+
+static const struct usb_action tas5130c_vf0250_InitialScale[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */
+ {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */
+ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc, */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc, */
+ {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc, */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc, */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc, */
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc, */
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc, */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc, */
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc, */
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc,
+ * 8<->6 */
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc,
+ * 8<->6 */
+ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */
+ {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */
+ {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */
+ {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */
+ {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */
+ {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
+ {0xaa, 0x01, 0x0000},
+ {0xaa, 0x01, 0x0000},
+ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */
+ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */
+ {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */
+ {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */
+ {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */
+ {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */
+ {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */
+ {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */
+ {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */
+ {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */
+ {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */
+ {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */
+ {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */
+ {0xa0, 0x00, 0x0039},
+ {0xa1, 0x01, 0x0037},
+ {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */
+ {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa (e6 -> e8) */
+ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */
+ {0xaa, 0x19, 0x0088}, /* 00,19,88,aa, */
+ {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */
+ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc, */
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc, */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc, */
+ {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc, */
+ {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc, */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc, */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */
+ {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */
+ {0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */
+ {0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */
+ {}
+};
+/* "50HZ" light frequency banding filter */
+static const struct usb_action tas5130c_vf0250_50HZ[] = {
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
+ {0xaa, 0x84, 0x00aa}, /* 00,84,aa,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
+ {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0d,cc, */
+ {0xa0, 0xa8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc, */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */
+ {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc, */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */
+ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */
+ {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */
+ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */
+ {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */
+ {}
+};
+
+/* "50HZScale" light frequency banding filter */
+static const struct usb_action tas5130c_vf0250_50HZScale[] = {
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0003}, /* 00,83,03,aa */
+ {0xaa, 0x84, 0x0054}, /* 00,84,54,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
+ {0xa0, 0x0d, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0d,cc, */
+ {0xa0, 0x50, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc, */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */
+ {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,8e,cc, */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */
+ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */
+ {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */
+ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */
+ {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */
+ {}
+};
+
+/* "60HZ" light frequency banding filter */
+static const struct usb_action tas5130c_vf0250_60HZ[] = {
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
+ {0xaa, 0x84, 0x0062}, /* 00,84,62,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
+ {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */
+ {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */
+ {0xa0, 0x3b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3b,cc, */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */
+ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */
+ {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */
+ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */
+ {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */
+ {}
+};
+
+/* "60HZScale" light frequency banding ilter */
+static const struct usb_action tas5130c_vf0250_60HZScale[] = {
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */
+ {0xaa, 0x84, 0x00c4}, /* 00,84,c4,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
+ {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,1,0b,cc, */
+ {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,2,10,cc, */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,5,00,cc, */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,6,00,cc, */
+ {0xa0, 0x76, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,7,76,cc, */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,c,0e,cc, */
+ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,f,15,cc, */
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,9,10,cc, */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,a,24,cc, */
+ {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,d,62,cc, */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,e,90,cc, */
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,f,c8,cc, */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,0,ff,cc, */
+ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,d,58,cc, */
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */
+ {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,d,78,cc */
+ {}
+};
+
+/* "NoFliker" light frequency banding flter */
+static const struct usb_action tas5130c_vf0250_NoFliker[] = {
+ {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
+ {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,0,00,cc, */
+ {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */
+ {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */
+ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */
+ {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */
+ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */
+ {0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,03,cc */
+ {}
+};
+
+/* "NoFlikerScale" light frequency banding filter */
+static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
+ {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
+ {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
+ {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc, */
+ {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc, */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */
+ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */
+ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */
+ {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */
+ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */
+ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */
+ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */
+ {0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,03,cc */
+ {}
+};
+
+static int reg_r_i(struct gspca_dev *gspca_dev,
+ __u16 index)
+{
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0xa1,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x01, /* value */
+ index, gspca_dev->usb_buf, 1,
+ 500);
+ return gspca_dev->usb_buf[0];
+}
+
+static int reg_r(struct gspca_dev *gspca_dev,
+ __u16 index)
+{
+ int ret;
+
+ ret = reg_r_i(gspca_dev, index);
+ PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret);
+ return ret;
+}
+
+static void reg_w_i(struct usb_device *dev,
+ __u8 value,
+ __u16 index)
+{
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0xa0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0,
+ 500);
+}
+
+static void reg_w(struct usb_device *dev,
+ __u8 value,
+ __u16 index)
+{
+ PDEBUG(D_USBO, "reg w %02x -> [%04x]", value, index);
+ reg_w_i(dev, value, index);
+}
+
+static __u16 i2c_read(struct gspca_dev *gspca_dev,
+ __u8 reg)
+{
+ __u8 retbyte;
+ __u8 retval[2];
+
+ reg_w_i(gspca_dev->dev, reg, 0x92);
+ reg_w_i(gspca_dev->dev, 0x02, 0x90); /* <- read command */
+ msleep(25);
+ retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */
+ retval[0] = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */
+ retval[1] = reg_r_i(gspca_dev, 0x0096); /* read Hightbyte */
+ PDEBUG(D_USBO, "i2c r [%02x] -> (%02x) %02x%02x",
+ reg, retbyte, retval[1], retval[0]);
+ return (retval[1] << 8) | retval[0];
+}
+
+static __u8 i2c_write(struct gspca_dev *gspca_dev,
+ __u8 reg,
+ __u8 valL,
+ __u8 valH)
+{
+ __u8 retbyte;
+
+ reg_w_i(gspca_dev->dev, reg, 0x92);
+ reg_w_i(gspca_dev->dev, valL, 0x93);
+ reg_w_i(gspca_dev->dev, valH, 0x94);
+ reg_w_i(gspca_dev->dev, 0x01, 0x90); /* <- write command */
+ msleep(5);
+ retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */
+ PDEBUG(D_USBO, "i2c w [%02x] %02x%02x (%02x)",
+ reg, valH, valL, retbyte);
+ return retbyte;
+}
+
+static void usb_exchange(struct gspca_dev *gspca_dev,
+ const struct usb_action *action)
+{
+ while (action->req) {
+ switch (action->req) {
+ case 0xa0: /* write register */
+ reg_w(gspca_dev->dev, action->val, action->idx);
+ break;
+ case 0xa1: /* read status */
+ reg_r(gspca_dev, action->idx);
+ break;
+ case 0xaa:
+ i2c_write(gspca_dev,
+ action->val, /* reg */
+ action->idx & 0xff, /* valL */
+ action->idx >> 8); /* valH */
+ break;
+ default:
+/* case 0xdd: * delay */
+ msleep(action->val / 64 + 10);
+ break;
+ }
+ action++;
+/* msleep(1); */
+ }
+}
+
+static void setmatrix(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ const __u8 *matrix;
+ static const __u8 gc0305_matrix[9] =
+ {0x50, 0xf8, 0xf8, 0xf8, 0x50, 0xf8, 0xf8, 0xf8, 0x50};
+ static const __u8 ov7620_matrix[9] =
+ {0x58, 0xf4, 0xf4, 0xf4, 0x58, 0xf4, 0xf4, 0xf4, 0x58};
+ static const __u8 po2030_matrix[9] =
+ {0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60};
+
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ matrix = gc0305_matrix;
+ break;
+ case SENSOR_MC501CB:
+ return; /* no matrix? */
+ case SENSOR_OV7620:
+/* case SENSOR_OV7648: */
+ matrix = ov7620_matrix;
+ break;
+ case SENSOR_PO2030:
+ matrix = po2030_matrix;
+ break;
+ case SENSOR_TAS5130C_VF0250: /* no matrix? */
+ return;
+ default: /* matrix already loaded */
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(ov7620_matrix); i++)
+ reg_w(gspca_dev->dev, matrix[i], 0x010a + i);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 brightness;
+
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ case SENSOR_PO2030:
+ return;
+ }
+/*fixme: is it really write to 011d and 018d for all other sensors? */
+ brightness = sd->brightness;
+ reg_w(gspca_dev->dev, brightness, 0x011d);
+ if (brightness < 0x70)
+ brightness += 0x10;
+ else
+ brightness = 0x80;
+ reg_w(gspca_dev->dev, brightness, 0x018d);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int sharpness;
+ static const __u8 sharpness_tb[][2] = {
+ {0x02, 0x03},
+ {0x04, 0x07},
+ {0x08, 0x0f},
+ {0x10, 0x1e}
+ };
+
+ sharpness = sd->sharpness;
+ reg_w(dev, sharpness_tb[sharpness][0], 0x01c6);
+ reg_r(gspca_dev, 0x01c8);
+ reg_r(gspca_dev, 0x01c9);
+ reg_r(gspca_dev, 0x01ca);
+ reg_w(dev, sharpness_tb[sharpness][1], 0x01cb);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ const __u8 *Tgamma, *Tgradient;
+ int g, i, k;
+ static const __u8 kgamma_tb[16] = /* delta for contrast */
+ {0x15, 0x0d, 0x0a, 0x09, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
+ static const __u8 kgrad_tb[16] =
+ {0x1b, 0x06, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x04};
+ static const __u8 Tgamma_1[16] =
+ {0x00, 0x00, 0x03, 0x0d, 0x1b, 0x2e, 0x45, 0x5f,
+ 0x79, 0x93, 0xab, 0xc1, 0xd4, 0xe5, 0xf3, 0xff};
+ static const __u8 Tgradient_1[16] =
+ {0x00, 0x01, 0x05, 0x0b, 0x10, 0x15, 0x18, 0x1a,
+ 0x1a, 0x18, 0x16, 0x14, 0x12, 0x0f, 0x0d, 0x06};
+ static const __u8 Tgamma_2[16] =
+ {0x01, 0x0c, 0x1f, 0x3a, 0x53, 0x6d, 0x85, 0x9c,
+ 0xb0, 0xc2, 0xd1, 0xde, 0xe9, 0xf2, 0xf9, 0xff};
+ static const __u8 Tgradient_2[16] =
+ {0x05, 0x0f, 0x16, 0x1a, 0x19, 0x19, 0x17, 0x15,
+ 0x12, 0x10, 0x0e, 0x0b, 0x09, 0x08, 0x06, 0x03};
+ static const __u8 Tgamma_3[16] =
+ {0x04, 0x16, 0x30, 0x4e, 0x68, 0x81, 0x98, 0xac,
+ 0xbe, 0xcd, 0xda, 0xe4, 0xed, 0xf5, 0xfb, 0xff};
+ static const __u8 Tgradient_3[16] =
+ {0x0c, 0x16, 0x1b, 0x1c, 0x19, 0x18, 0x15, 0x12,
+ 0x10, 0x0d, 0x0b, 0x09, 0x08, 0x06, 0x05, 0x03};
+ static const __u8 Tgamma_4[16] =
+ {0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff};
+ static const __u8 Tgradient_4[16] =
+ {0x26, 0x22, 0x20, 0x1c, 0x16, 0x13, 0x10, 0x0d,
+ 0x0b, 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02};
+ static const __u8 Tgamma_5[16] =
+ {0x20, 0x4b, 0x6e, 0x8d, 0xa3, 0xb5, 0xc5, 0xd2,
+ 0xdc, 0xe5, 0xec, 0xf2, 0xf6, 0xfa, 0xfd, 0xff};
+ static const __u8 Tgradient_5[16] =
+ {0x37, 0x26, 0x20, 0x1a, 0x14, 0x10, 0x0e, 0x0b,
+ 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02};
+ static const __u8 Tgamma_6[16] = /* ?? was gamma 5 */
+ {0x24, 0x44, 0x64, 0x84, 0x9d, 0xb2, 0xc4, 0xd3,
+ 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff};
+ static const __u8 Tgradient_6[16] =
+ {0x18, 0x20, 0x20, 0x1c, 0x16, 0x13, 0x10, 0x0e,
+ 0x0b, 0x09, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01};
+ static const __u8 *gamma_tb[] = {
+ NULL, Tgamma_1, Tgamma_2,
+ Tgamma_3, Tgamma_4, Tgamma_5, Tgamma_6
+ };
+ static const __u8 *gradient_tb[] = {
+ NULL, Tgradient_1, Tgradient_2,
+ Tgradient_3, Tgradient_4, Tgradient_5, Tgradient_6
+ };
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ __u8 v[16];
+#endif
+
+ Tgamma = gamma_tb[sd->gamma];
+ Tgradient = gradient_tb[sd->gamma];
+
+ k = (sd->contrast - 128) /* -128 / 128 */
+ * Tgamma[0];
+ PDEBUG(D_CONF, "gamma:%d contrast:%d gamma coeff: %d/128",
+ sd->gamma, sd->contrast, k);
+ for (i = 0; i < 16; i++) {
+ g = Tgamma[i] + kgamma_tb[i] * k / 128;
+ if (g > 0xff)
+ g = 0xff;
+ else if (g <= 0)
+ g = 1;
+ reg_w(dev, g, 0x0120 + i); /* gamma */
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (gspca_debug & D_CONF)
+ v[i] = g;
+#endif
+ }
+ PDEBUG(D_CONF, "tb: %02x %02x %02x %02x %02x %02x %02x %02x",
+ v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+ PDEBUG(D_CONF, " %02x %02x %02x %02x %02x %02x %02x %02x",
+ v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]);
+ for (i = 0; i < 16; i++) {
+ g = Tgradient[i] - kgrad_tb[i] * k / 128;
+ if (g > 0xff)
+ g = 0xff;
+ else if (g <= 0) {
+ if (i != 15)
+ g = 0;
+ else
+ g = 1;
+ }
+ reg_w(dev, g, 0x0130 + i); /* gradient */
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (gspca_debug & D_CONF)
+ v[i] = g;
+#endif
+ }
+ PDEBUG(D_CONF, " %02x %02x %02x %02x %02x %02x %02x %02x",
+ v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+ PDEBUG(D_CONF, " %02x %02x %02x %02x %02x %02x %02x %02x",
+ v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]);
+}
+
+static void setquality(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 quality;
+ __u8 frxt;
+
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ case SENSOR_PO2030:
+ return;
+ }
+/*fixme: is it really 0008 0007 0018 for all other sensors? */
+ quality = sd->qindex;
+ reg_w(dev, quality, 0x0008);
+ frxt = 0x30;
+ reg_w(dev, frxt, 0x0007);
+ switch (quality) {
+ case 0:
+ case 1:
+ case 2:
+ frxt = 0xff;
+ break;
+ case 3:
+ frxt = 0xf0;
+ break;
+ case 4:
+ frxt = 0xe0;
+ break;
+ case 5:
+ frxt = 0x20;
+ break;
+ }
+ reg_w(dev, frxt, 0x0018);
+}
+
+/* Matches the sensor's internal frame rate to the lighting frequency.
+ * Valid frequencies are:
+ * 50Hz, for European and Asian lighting (default)
+ * 60Hz, for American lighting
+ * 0 = No Fliker (for outdoore usage)
+ * Returns: 0 for success
+ */
+static int setlightfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, mode;
+ const struct usb_action *zc3_freq;
+ static const struct usb_action *freq_tb[SENSOR_MAX][6] = {
+/* SENSOR_CS2102 0 */
+ {cs2102_NoFliker, cs2102_NoFlikerScale,
+ cs2102_50HZ, cs2102_50HZScale,
+ cs2102_60HZ, cs2102_60HZScale},
+/* SENSOR_CS2102K 1 */
+ {cs2102_NoFliker, cs2102_NoFlikerScale,
+ cs2102_50HZ, cs2102_50HZScale,
+ cs2102_60HZ, cs2102_60HZScale},
+/* SENSOR_GC0305 2 */
+ {gc0305_NoFliker, gc0305_NoFliker,
+ gc0305_50HZ, gc0305_50HZ,
+ gc0305_60HZ, gc0305_60HZ},
+/* SENSOR_HDCS2020 3 */
+ {NULL, NULL,
+ NULL, NULL,
+ NULL, NULL},
+/* SENSOR_HDCS2020b 4 */
+ {hdcs2020b_NoFliker, hdcs2020b_NoFliker,
+ hdcs2020b_50HZ, hdcs2020b_50HZ,
+ hdcs2020b_60HZ, hdcs2020b_60HZ},
+/* SENSOR_HV7131B 5 */
+ {NULL, NULL,
+ NULL, NULL,
+ NULL, NULL},
+/* SENSOR_HV7131C 6 */
+ {NULL, NULL,
+ NULL, NULL,
+ NULL, NULL},
+/* SENSOR_ICM105A 7 */
+ {icm105a_NoFliker, icm105a_NoFlikerScale,
+ icm105a_50HZ, icm105a_50HZScale,
+ icm105a_60HZ, icm105a_60HZScale},
+/* SENSOR_MC501CB 8 */
+ {MC501CB_NoFliker, MC501CB_NoFlikerScale,
+ MC501CB_50HZ, MC501CB_50HZScale,
+ MC501CB_60HZ, MC501CB_60HZScale},
+/* SENSOR_OV7620 9 */
+ {OV7620_NoFliker, OV7620_NoFliker,
+ OV7620_50HZ, OV7620_50HZ,
+ OV7620_60HZ, OV7620_60HZ},
+/* SENSOR_OV7630C 10 */
+ {NULL, NULL,
+ NULL, NULL,
+ NULL, NULL},
+/* SENSOR_PAS106 11 */
+ {pas106b_NoFliker, pas106b_NoFliker,
+ pas106b_50HZ, pas106b_50HZ,
+ pas106b_60HZ, pas106b_60HZ},
+/* SENSOR_PB0330 12 */
+ {pb0330_NoFliker, pb0330_NoFlikerScale,
+ pb0330_50HZ, pb0330_50HZScale,
+ pb0330_60HZ, pb0330_60HZScale},
+/* SENSOR_PO2030 13 */
+ {PO2030_NoFliker, PO2030_NoFliker,
+ PO2030_50HZ, PO2030_50HZ,
+ PO2030_60HZ, PO2030_60HZ},
+/* SENSOR_TAS5130CK 14 */
+ {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+ tas5130cxx_50HZ, tas5130cxx_50HZScale,
+ tas5130cxx_60HZ, tas5130cxx_60HZScale},
+/* SENSOR_TAS5130CXX 15 */
+ {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+ tas5130cxx_50HZ, tas5130cxx_50HZScale,
+ tas5130cxx_60HZ, tas5130cxx_60HZScale},
+/* SENSOR_TAS5130C_VF0250 16 */
+ {tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale,
+ tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
+ tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale},
+ };
+
+ i = sd->lightfreq * 2;
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ if (!mode)
+ i++; /* 640x480 */
+ zc3_freq = freq_tb[(int) sd->sensor][i];
+ if (zc3_freq != NULL) {
+ usb_exchange(gspca_dev, zc3_freq);
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ if (mode /* if 320x240 */
+ && sd->lightfreq == 1) /* and 50Hz */
+ reg_w(gspca_dev->dev, 0x85, 0x018d);
+ /* win: 0x80, 0x018d */
+ break;
+ case SENSOR_OV7620:
+ if (!mode) { /* if 640x480 */
+ if (sd->lightfreq != 0) /* and 50 or 60 Hz */
+ reg_w(gspca_dev->dev, 0x40, 0x0002);
+ else
+ reg_w(gspca_dev->dev, 0x44, 0x0002);
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 autoval;
+
+ if (sd->autogain)
+ autoval = 0x42;
+ else
+ autoval = 0x02;
+ reg_w(gspca_dev->dev, autoval, 0x0180);
+}
+
+static void send_unknown(struct usb_device *dev, int sensor)
+{
+ reg_w(dev, 0x01, 0x0000); /* led off */
+ switch (sensor) {
+ case SENSOR_PAS106:
+ reg_w(dev, 0x03, 0x003a);
+ reg_w(dev, 0x0c, 0x003b);
+ reg_w(dev, 0x08, 0x0038);
+ break;
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ case SENSOR_PB0330:
+ case SENSOR_PO2030:
+ reg_w(dev, 0x0d, 0x003a);
+ reg_w(dev, 0x02, 0x003b);
+ reg_w(dev, 0x00, 0x0038);
+ break;
+ }
+}
+
+/* start probe 2 wires */
+static void start_2wr_probe(struct usb_device *dev, int sensor)
+{
+ reg_w(dev, 0x01, 0x0000);
+ reg_w(dev, sensor, 0x0010);
+ reg_w(dev, 0x01, 0x0001);
+ reg_w(dev, 0x03, 0x0012);
+ reg_w(dev, 0x01, 0x0012);
+/* msleep(2); */
+}
+
+static int sif_probe(struct gspca_dev *gspca_dev)
+{
+ __u16 checkword;
+
+ start_2wr_probe(gspca_dev->dev, 0x0f); /* PAS106 */
+ reg_w(gspca_dev->dev, 0x08, 0x008d);
+ msleep(150);
+ checkword = ((i2c_read(gspca_dev, 0x00) & 0x0f) << 4)
+ | ((i2c_read(gspca_dev, 0x01) & 0xf0) >> 4);
+ PDEBUG(D_PROBE, "probe sif 0x%04x", checkword);
+ if (checkword == 0x0007) {
+ send_unknown(gspca_dev->dev, SENSOR_PAS106);
+ return 0x0f; /* PAS106 */
+ }
+ return -1;
+}
+
+static int vga_2wr_probe(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 retbyte;
+ __u16 checkword;
+
+ start_2wr_probe(dev, 0x00); /* HV7131B */
+ i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
+ retbyte = i2c_read(gspca_dev, 0x01);
+ if (retbyte != 0)
+ return 0x00; /* HV7131B */
+
+ start_2wr_probe(dev, 0x04); /* CS2102 */
+ i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
+ retbyte = i2c_read(gspca_dev, 0x01);
+ if (retbyte != 0)
+ return 0x04; /* CS2102 */
+
+ start_2wr_probe(dev, 0x06); /* OmniVision */
+ reg_w(dev, 0x08, 0x8d);
+ i2c_write(gspca_dev, 0x11, 0xaa, 0x00);
+ retbyte = i2c_read(gspca_dev, 0x11);
+ if (retbyte != 0) {
+ /* (should have returned 0xaa) --> Omnivision? */
+ /* reg_r 0x10 -> 0x06 --> */
+ goto ov_check;
+ }
+
+ start_2wr_probe(dev, 0x08); /* HDCS2020 */
+ i2c_write(gspca_dev, 0x15, 0xaa, 0x00);
+ retbyte = i2c_read(gspca_dev, 0x15);
+ if (retbyte != 0)
+ return 0x08; /* HDCS2020 */
+
+ start_2wr_probe(dev, 0x0a); /* PB0330 */
+ i2c_write(gspca_dev, 0x07, 0xaa, 0xaa);
+ retbyte = i2c_read(gspca_dev, 0x07);
+ if (retbyte != 0)
+ return 0x0a; /* PB0330 */
+ retbyte = i2c_read(gspca_dev, 0x03);
+ if (retbyte != 0)
+ return 0x0a; /* PB0330 ?? */
+ retbyte = i2c_read(gspca_dev, 0x04);
+ if (retbyte != 0)
+ return 0x0a; /* PB0330 ?? */
+
+ start_2wr_probe(dev, 0x0c); /* ICM105A */
+ i2c_write(gspca_dev, 0x01, 0x11, 0x00);
+ retbyte = i2c_read(gspca_dev, 0x01);
+ if (retbyte != 0)
+ return 0x0c; /* ICM105A */
+
+ start_2wr_probe(dev, 0x0e); /* PAS202BCB */
+ reg_w(dev, 0x08, 0x8d);
+ i2c_write(gspca_dev, 0x03, 0xaa, 0x00);
+ msleep(500);
+ retbyte = i2c_read(gspca_dev, 0x03);
+ if (retbyte != 0)
+ return 0x0e; /* PAS202BCB */
+
+ start_2wr_probe(dev, 0x02); /* ?? */
+ i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
+ retbyte = i2c_read(gspca_dev, 0x01);
+ if (retbyte != 0)
+ return 0x02; /* ?? */
+ov_check:
+ reg_r(gspca_dev, 0x0010); /* ?? */
+ reg_r(gspca_dev, 0x0010);
+
+ reg_w(dev, 0x01, 0x0000);
+ reg_w(dev, 0x01, 0x0001);
+ reg_w(dev, 0x06, 0x0010); /* OmniVision */
+ reg_w(dev, 0xa1, 0x008b);
+ reg_w(dev, 0x08, 0x008d);
+ msleep(500);
+ reg_w(dev, 0x01, 0x0012);
+ i2c_write(gspca_dev, 0x12, 0x80, 0x00); /* sensor reset */
+ retbyte = i2c_read(gspca_dev, 0x0a);
+ checkword = retbyte << 8;
+ retbyte = i2c_read(gspca_dev, 0x0b);
+ checkword |= retbyte;
+ PDEBUG(D_PROBE, "probe 2wr ov vga 0x%04x", checkword);
+ switch (checkword) {
+ case 0x7631: /* OV7630C */
+ reg_w(dev, 0x06, 0x0010);
+ break;
+ case 0x7620: /* OV7620 */
+ case 0x7648: /* OV7648 */
+ break;
+ default:
+ return -1; /* not OmniVision */
+ }
+ return checkword;
+}
+
+struct sensor_by_chipset_revision {
+ __u16 revision;
+ __u8 internal_sensor_id;
+};
+static const struct sensor_by_chipset_revision chipset_revision_sensor[] = {
+ {0xc001, 0x13}, /* MI0360 */
+ {0xe001, 0x13},
+ {0x8001, 0x13},
+ {0x8000, 0x14}, /* CS2102K */
+ {0x8400, 0x15}, /* TAS5130K */
+ {0, 0}
+};
+
+static int vga_3wr_probe(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int i;
+ __u8 retbyte;
+ __u16 checkword;
+
+/*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/
+ reg_w(dev, 0x02, 0x0010);
+ reg_r(gspca_dev, 0x10);
+ reg_w(dev, 0x01, 0x0000);
+ reg_w(dev, 0x00, 0x0010);
+ reg_w(dev, 0x01, 0x0001);
+ reg_w(dev, 0x91, 0x008b);
+ reg_w(dev, 0x03, 0x0012);
+ reg_w(dev, 0x01, 0x0012);
+ reg_w(dev, 0x05, 0x0012);
+ retbyte = i2c_read(gspca_dev, 0x14);
+ if (retbyte != 0)
+ return 0x11; /* HV7131R */
+ retbyte = i2c_read(gspca_dev, 0x15);
+ if (retbyte != 0)
+ return 0x11; /* HV7131R */
+ retbyte = i2c_read(gspca_dev, 0x16);
+ if (retbyte != 0)
+ return 0x11; /* HV7131R */
+
+ reg_w(dev, 0x02, 0x0010);
+ retbyte = reg_r(gspca_dev, 0x000b);
+ checkword = retbyte << 8;
+ retbyte = reg_r(gspca_dev, 0x000a);
+ checkword |= retbyte;
+ PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", checkword);
+ reg_r(gspca_dev, 0x0010);
+ /* this is tested only once anyway */
+ i = 0;
+ while (chipset_revision_sensor[i].revision) {
+ if (chipset_revision_sensor[i].revision == checkword) {
+ sd->chip_revision = checkword;
+ send_unknown(dev, SENSOR_PB0330);
+ return chipset_revision_sensor[i].internal_sensor_id;
+ }
+ i++;
+ }
+
+ reg_w(dev, 0x01, 0x0000);
+ reg_w(dev, 0x01, 0x0001);
+ reg_w(dev, 0xdd, 0x008b);
+ reg_w(dev, 0x0a, 0x0010);
+ reg_w(dev, 0x03, 0x0012);
+ reg_w(dev, 0x01, 0x0012);
+ retbyte = i2c_read(gspca_dev, 0x00);
+ if (retbyte != 0) {
+ PDEBUG(D_PROBE, "probe 3wr vga type 0a ?");
+ return 0x0a; /* ?? */
+ }
+
+ reg_w(dev, 0x01, 0x0000);
+ reg_w(dev, 0x01, 0x0001);
+ reg_w(dev, 0x98, 0x008b);
+ reg_w(dev, 0x01, 0x0010);
+ reg_w(dev, 0x03, 0x0012);
+ msleep(2);
+ reg_w(dev, 0x01, 0x0012);
+ retbyte = i2c_read(gspca_dev, 0x00);
+ if (retbyte != 0) {
+ PDEBUG(D_PROBE, "probe 3wr vga type %02x", retbyte);
+ send_unknown(dev, SENSOR_GC0305);
+ return retbyte; /* 0x29 = gc0305 - should continue? */
+ }
+
+ reg_w(dev, 0x01, 0x0000); /* check OmniVision */
+ reg_w(dev, 0x01, 0x0001);
+ reg_w(dev, 0xa1, 0x008b);
+ reg_w(dev, 0x08, 0x008d);
+ reg_w(dev, 0x06, 0x0010);
+ reg_w(dev, 0x01, 0x0012);
+ reg_w(dev, 0x05, 0x0012);
+ if (i2c_read(gspca_dev, 0x1c) == 0x7f /* OV7610 - manufacturer ID */
+ && i2c_read(gspca_dev, 0x1d) == 0xa2) {
+ send_unknown(dev, SENSOR_OV7620);
+ return 0x06; /* OmniVision confirm ? */
+ }
+
+ reg_w(dev, 0x01, 0x00);
+ reg_w(dev, 0x00, 0x02);
+ reg_w(dev, 0x01, 0x10);
+ reg_w(dev, 0x01, 0x01);
+ reg_w(dev, 0xee, 0x8b);
+ reg_w(dev, 0x03, 0x12);
+/* msleep(150); */
+ reg_w(dev, 0x01, 0x12);
+ reg_w(dev, 0x05, 0x12);
+ retbyte = i2c_read(gspca_dev, 0x00); /* ID 0 */
+ checkword = retbyte << 8;
+ retbyte = i2c_read(gspca_dev, 0x01); /* ID 1 */
+ checkword |= retbyte;
+ PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", checkword);
+ if (checkword == 0x2030) {
+ retbyte = i2c_read(gspca_dev, 0x02); /* revision number */
+ PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte);
+ send_unknown(dev, SENSOR_PO2030);
+ return checkword;
+ }
+
+ reg_w(dev, 0x01, 0x00);
+ reg_w(dev, 0x0a, 0x10);
+ reg_w(dev, 0xd3, 0x8b);
+ reg_w(dev, 0x01, 0x01);
+ reg_w(dev, 0x03, 0x12);
+ reg_w(dev, 0x01, 0x12);
+ reg_w(dev, 0x05, 0x01);
+ reg_w(dev, 0xd3, 0x8b);
+ retbyte = i2c_read(gspca_dev, 0x01);
+ if (retbyte != 0) {
+ PDEBUG(D_PROBE, "probe 3wr vga type 0a ?");
+ return 0x0a; /* ?? */
+ }
+ return -1;
+}
+
+static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int sensor, sensor2;
+
+ switch (sd->sensor) {
+ case SENSOR_MC501CB:
+ case SENSOR_TAS5130C_VF0250:
+ return -1; /* don't probe */
+ }
+ sensor = vga_2wr_probe(gspca_dev);
+ if (sensor >= 0) {
+ if (sensor < 0x7600)
+ return sensor;
+ /* next probe is needed for OmniVision ? */
+ }
+ sensor2 = vga_3wr_probe(gspca_dev);
+ if (sensor2 >= 0) {
+ if (sensor >= 0)
+ return sensor;
+ return sensor2;
+ }
+ return sif_probe(gspca_dev);
+}
+
+/* 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 sensor;
+ int vga = 1; /* 1: vga, 0: sif */
+ static const __u8 gamma[SENSOR_MAX] = {
+ 5, /* SENSOR_CS2102 0 */
+ 5, /* SENSOR_CS2102K 1 */
+ 4, /* SENSOR_GC0305 2 */
+ 4, /* SENSOR_HDCS2020 3 */
+ 4, /* SENSOR_HDCS2020b 4 */
+ 4, /* SENSOR_HV7131B 5 */
+ 4, /* SENSOR_HV7131C 6 */
+ 4, /* SENSOR_ICM105A 7 */
+ 4, /* SENSOR_MC501CB 8 */
+ 3, /* SENSOR_OV7620 9 */
+ 4, /* SENSOR_OV7630C 10 */
+ 4, /* SENSOR_PAS106 11 */
+ 4, /* SENSOR_PB0330 12 */
+ 4, /* SENSOR_PO2030 13 */
+ 4, /* SENSOR_TAS5130CK 14 */
+ 4, /* SENSOR_TAS5130CXX 15 */
+ 3, /* SENSOR_TAS5130C_VF0250 16 */
+ };
+
+ /* define some sensors from the vendor/product */
+ sd->sharpness = 2;
+ switch (id->idVendor) {
+ case 0x041e: /* Creative */
+ switch (id->idProduct) {
+ case 0x4051: /* zc301 chips */
+ case 0x4053:
+ sd->sensor = SENSOR_TAS5130C_VF0250;
+ break;
+ }
+ break;
+ case 0x046d: /* Logitech Labtec */
+ switch (id->idProduct) {
+ case 0x08dd:
+ sd->sensor = SENSOR_MC501CB;
+ break;
+ }
+ break;
+ case 0x0ac8: /* Vimicro z-star */
+ switch (id->idProduct) {
+ case 0x305b:
+ sd->sensor = SENSOR_TAS5130C_VF0250;
+ break;
+ }
+ break;
+ }
+ sensor = zcxx_probeSensor(gspca_dev);
+ if (sensor >= 0)
+ PDEBUG(D_PROBE, "probe sensor -> %02x", sensor);
+ if ((unsigned) force_sensor < SENSOR_MAX) {
+ sd->sensor = force_sensor;
+ PDEBUG(D_PROBE, "sensor forced to %d", force_sensor);
+ } else {
+ switch (sensor) {
+ case -1:
+ switch (sd->sensor) {
+ case SENSOR_MC501CB:
+ PDEBUG(D_PROBE, "Sensor MC501CB");
+ break;
+ case SENSOR_TAS5130C_VF0250:
+ PDEBUG(D_PROBE, "Sensor Tas5130 (VF0250)");
+ break;
+ default:
+ PDEBUG(D_PROBE,
+ "Sensor UNKNOW_0 force Tas5130");
+ sd->sensor = SENSOR_TAS5130CXX;
+ }
+ break;
+ case 0:
+ PDEBUG(D_PROBE, "Find Sensor HV7131B");
+ sd->sensor = SENSOR_HV7131B;
+ break;
+ case 0x04:
+ PDEBUG(D_PROBE, "Find Sensor CS2102");
+ sd->sensor = SENSOR_CS2102;
+ break;
+ case 0x08:
+ PDEBUG(D_PROBE, "Find Sensor HDCS2020(b)");
+ sd->sensor = SENSOR_HDCS2020b;
+ break;
+ case 0x0a:
+ PDEBUG(D_PROBE,
+ "Find Sensor PB0330. Chip revision %x",
+ sd->chip_revision);
+ sd->sensor = SENSOR_PB0330;
+ break;
+ case 0x0c:
+ PDEBUG(D_PROBE, "Find Sensor ICM105A");
+ sd->sensor = SENSOR_ICM105A;
+ break;
+ case 0x0e:
+ PDEBUG(D_PROBE, "Find Sensor HDCS2020");
+ sd->sensor = SENSOR_HDCS2020;
+ sd->sharpness = 1;
+ break;
+ case 0x0f:
+ PDEBUG(D_PROBE, "Find Sensor PAS106");
+ sd->sensor = SENSOR_PAS106;
+ vga = 0; /* SIF */
+ break;
+ case 0x10:
+ case 0x12:
+ PDEBUG(D_PROBE, "Find Sensor TAS5130");
+ sd->sensor = SENSOR_TAS5130CXX;
+ break;
+ case 0x11:
+ PDEBUG(D_PROBE, "Find Sensor HV7131R(c)");
+ sd->sensor = SENSOR_HV7131C;
+ break;
+ case 0x13:
+ PDEBUG(D_PROBE,
+ "Find Sensor MI0360. Chip revision %x",
+ sd->chip_revision);
+ sd->sensor = SENSOR_PB0330;
+ break;
+ case 0x14:
+ PDEBUG(D_PROBE,
+ "Find Sensor CS2102K?. Chip revision %x",
+ sd->chip_revision);
+ sd->sensor = SENSOR_CS2102K;
+ break;
+ case 0x15:
+ PDEBUG(D_PROBE,
+ "Find Sensor TAS5130CK?. Chip revision %x",
+ sd->chip_revision);
+ sd->sensor = SENSOR_TAS5130CK;
+ break;
+ case 0x29:
+ PDEBUG(D_PROBE, "Find Sensor GC0305");
+ sd->sensor = SENSOR_GC0305;
+ break;
+ case 0x2030:
+ PDEBUG(D_PROBE, "Find Sensor PO2030");
+ sd->sensor = SENSOR_PO2030;
+ sd->sharpness = 0; /* from win traces */
+ break;
+ case 0x7620:
+ PDEBUG(D_PROBE, "Find Sensor OV7620");
+ sd->sensor = SENSOR_OV7620;
+ break;
+ case 0x7648:
+ PDEBUG(D_PROBE, "Find Sensor OV7648");
+ sd->sensor = SENSOR_OV7620; /* same sensor (?) */
+ break;
+ default:
+ PDEBUG(D_ERR|D_PROBE, "Unknown sensor %02x", sensor);
+ return -EINVAL;
+ }
+ }
+ if (sensor < 0x20) {
+ if (sensor == -1 || sensor == 0x10 || sensor == 0x12)
+ reg_w(gspca_dev->dev, 0x02, 0x0010);
+ else
+ reg_w(gspca_dev->dev, sensor & 0x0f, 0x0010);
+ reg_r(gspca_dev, 0x0010);
+ }
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+/*fixme:test*/
+ gspca_dev->nbalt--;
+ if (vga) {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+ } else {
+ cam->cam_mode = sif_mode;
+ cam->nmodes = ARRAY_SIZE(sif_mode);
+ }
+ sd->qindex = 1;
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->gamma = gamma[(int) sd->sensor];
+ sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+ sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
+ sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
+
+ /* switch the led off */
+ reg_w(gspca_dev->dev, 0x01, 0x0000);
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev->dev, 0x01, 0x0000);
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ const struct usb_action *zc3_init;
+ int mode;
+ static const struct usb_action *init_tb[SENSOR_MAX][2] = {
+ {cs2102_InitialScale, cs2102_Initial}, /* 0 */
+ {cs2102K_InitialScale, cs2102K_Initial}, /* 1 */
+ {gc0305_Initial, gc0305_InitialScale}, /* 2 */
+ {hdcs2020xx_InitialScale, hdcs2020xx_Initial}, /* 3 */
+ {hdcs2020xb_InitialScale, hdcs2020xb_Initial}, /* 4 */
+ {hv7131bxx_InitialScale, hv7131bxx_Initial}, /* 5 */
+ {hv7131cxx_InitialScale, hv7131cxx_Initial}, /* 6 */
+ {icm105axx_InitialScale, icm105axx_Initial}, /* 7 */
+ {MC501CB_InitialScale, MC501CB_Initial}, /* 9 */
+ {OV7620_mode0, OV7620_mode1}, /* 9 */
+ {ov7630c_InitialScale, ov7630c_Initial}, /* 10 */
+ {pas106b_InitialScale, pas106b_Initial}, /* 11 */
+ {pb0330xx_InitialScale, pb0330xx_Initial}, /* 12 */
+/* or {pb03303x_InitialScale, pb03303x_Initial}, */
+ {PO2030_mode0, PO2030_mode1}, /* 13 */
+ {tas5130CK_InitialScale, tas5130CK_Initial}, /* 14 */
+ {tas5130cxx_InitialScale, tas5130cxx_Initial}, /* 15 */
+ {tas5130c_vf0250_InitialScale, tas5130c_vf0250_Initial},
+ /* 16 */
+ };
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ zc3_init = init_tb[(int) sd->sensor][mode];
+ switch (sd->sensor) {
+ case SENSOR_HV7131B:
+ case SENSOR_HV7131C:
+ zcxx_probeSensor(gspca_dev);
+ break;
+ case SENSOR_PAS106:
+ usb_exchange(gspca_dev, pas106b_Initial_com);
+ break;
+ case SENSOR_PB0330:
+ if (mode) {
+ if (sd->chip_revision == 0xc001
+ || sd->chip_revision == 0xe001
+ || sd->chip_revision == 0x8001)
+ zc3_init = pb03303x_Initial;
+ } else {
+ if (sd->chip_revision == 0xc001
+ || sd->chip_revision == 0xe001
+ || sd->chip_revision == 0x8001)
+ zc3_init = pb03303x_InitialScale;
+ }
+ break;
+ }
+ usb_exchange(gspca_dev, zc3_init);
+
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ case SENSOR_PO2030:
+ msleep(100); /* ?? */
+ reg_r(gspca_dev, 0x0002); /* --> 0x40 */
+ reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
+ reg_w(dev, 0x15, 0x01ae);
+ reg_w(dev, 0x0d, 0x003a);
+ reg_w(dev, 0x02, 0x003b);
+ reg_w(dev, 0x00, 0x0038);
+ break;
+ }
+
+ setmatrix(gspca_dev);
+ setbrightness(gspca_dev);
+ switch (sd->sensor) {
+ case SENSOR_OV7620:
+ reg_r(gspca_dev, 0x0008);
+ reg_w(dev, 0x00, 0x0008);
+ break;
+ case SENSOR_GC0305:
+ reg_r(gspca_dev, 0x0008);
+ /* fall thru */
+ case SENSOR_PO2030:
+ reg_w(dev, 0x03, 0x0008);
+ break;
+ }
+ setsharpness(gspca_dev);
+
+ /* set the gamma tables when not set */
+ switch (sd->sensor) {
+ case SENSOR_CS2102: /* gamma set in xxx_Initial */
+ case SENSOR_CS2102K:
+ case SENSOR_HDCS2020:
+ case SENSOR_HDCS2020b:
+ case SENSOR_PB0330: /* pb with chip_revision - see above */
+ case SENSOR_OV7630C:
+ case SENSOR_TAS5130CK:
+ break;
+ default:
+ setcontrast(gspca_dev);
+ break;
+ }
+ setmatrix(gspca_dev); /* one more time? */
+ switch (sd->sensor) {
+ case SENSOR_OV7620:
+ reg_r(gspca_dev, 0x0180); /* from win */
+ reg_w(dev, 0x00, 0x0180);
+ break;
+ default:
+ setquality(gspca_dev);
+ break;
+ }
+ setlightfreq(gspca_dev);
+
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
+ reg_w(dev, 0x15, 0x01ae);
+ sd->autogain = 0;
+ break;
+ case SENSOR_PO2030:
+ reg_w(dev, 0x40, 0x0117); /* (from win traces) */
+ reg_r(gspca_dev, 0x0180);
+ break;
+ }
+
+ setautogain(gspca_dev);
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+/* setlightfreq(gspca_dev); ?? (end: 80 -> [18d]) */
+ reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
+ reg_w(dev, 0x15, 0x01ae);
+ reg_w(dev, 0x40, 0x0180);
+ reg_w(dev, 0x40, 0x0117);
+ reg_r(gspca_dev, 0x0180);
+ sd->autogain = 1;
+ setautogain(gspca_dev);
+ break;
+ case SENSOR_OV7620:
+ i2c_read(gspca_dev, 0x13); /*fixme: returns 0xa3 */
+ i2c_write(gspca_dev, 0x13, 0xa3, 0x00);
+ /*fixme: returned value to send? */
+ reg_w(dev, 0x40, 0x0117); /* (from win traces) */
+ reg_r(gspca_dev, 0x0180);
+ setautogain(gspca_dev);
+ msleep(500);
+ break;
+ case SENSOR_PO2030:
+ msleep(500);
+ reg_r(gspca_dev, 0x0008);
+ reg_r(gspca_dev, 0x0007);
+ reg_w(dev, 0x00, 0x0007); /* (from win traces) */
+ reg_w(dev, 0x02, 0x0008);
+ break;
+ }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ send_unknown(gspca_dev->dev, sd->sensor);
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame,
+ __u8 *data,
+ int len)
+{
+
+ if (data[0] == 0xff && data[1] == 0xd8) { /* start of frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+ /* put the JPEG header in the new frame */
+ jpeg_put_header(gspca_dev, frame,
+ ((struct sd *) gspca_dev)->qindex,
+ 0x21);
+ /* remove the webcam's header:
+ * ff d8 ff fe 00 0e 00 00 ss ss 00 01 ww ww hh hh pp pp
+ * - 'ss ss' is the frame sequence number (BE)
+ * - 'ww ww' and 'hh hh' are the window dimensions (BE)
+ * - 'pp pp' is the packet sequence number (BE)
+ */
+ data += 18;
+ len -= 18;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (gspca_dev->streaming)
+ setautogain(gspca_dev);
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gamma = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->gamma;
+ return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->lightfreq = val;
+ if (gspca_dev->streaming)
+ setlightfreq(gspca_dev);
+ return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->lightfreq;
+ return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->sharpness = val;
+ if (gspca_dev->streaming)
+ setsharpness(gspca_dev);
+ return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->sharpness;
+ return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+ strcpy((char *) menu->name, "NoFliker");
+ return 0;
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
+};
+
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x041e), DVNM("Creative WebCam Live!")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x041e, 0x4017), DVNM("Creative Webcam Mobile PD1090")},
+ {USB_DEVICE(0x041e, 0x401c), DVNM("Creative NX")},
+ {USB_DEVICE(0x041e, 0x401e), DVNM("Creative Nx Pro")},
+ {USB_DEVICE(0x041e, 0x401f), DVNM("Creative Webcam Notebook PD1171")},
+#endif
+ {USB_DEVICE(0x041e, 0x4029), DVNM("Creative WebCam Vista Pro")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x041e, 0x4034), DVNM("Creative Instant P0620")},
+ {USB_DEVICE(0x041e, 0x4035), DVNM("Creative Instant P0620D")},
+ {USB_DEVICE(0x041e, 0x4036), DVNM("Creative Live !")},
+ {USB_DEVICE(0x041e, 0x403a), DVNM("Creative Nx Pro 2")},
+#endif
+ {USB_DEVICE(0x041e, 0x4051), DVNM("Creative Notebook Pro (VF0250)")},
+ {USB_DEVICE(0x041e, 0x4053), DVNM("Creative Live!Cam Video IM")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x0458, 0x7007), DVNM("Genius VideoCam V2")},
+ {USB_DEVICE(0x0458, 0x700c), DVNM("Genius VideoCam V3")},
+ {USB_DEVICE(0x0458, 0x700f), DVNM("Genius VideoCam Web V2")},
+#endif
+ {USB_DEVICE(0x0461, 0x0a00), DVNM("MicroInnovation WebCam320")},
+ {USB_DEVICE(0x046d, 0x08a0), DVNM("Logitech QC IM")},
+ {USB_DEVICE(0x046d, 0x08a1), DVNM("Logitech QC IM 0x08A1 +sound")},
+ {USB_DEVICE(0x046d, 0x08a2), DVNM("Labtec Webcam Pro")},
+ {USB_DEVICE(0x046d, 0x08a3), DVNM("Logitech QC Chat")},
+ {USB_DEVICE(0x046d, 0x08a6), DVNM("Logitech QCim")},
+ {USB_DEVICE(0x046d, 0x08a7), DVNM("Logitech QuickCam Image")},
+ {USB_DEVICE(0x046d, 0x08a9), DVNM("Logitech Notebook Deluxe")},
+ {USB_DEVICE(0x046d, 0x08aa), DVNM("Labtec Webcam Notebook")},
+ {USB_DEVICE(0x046d, 0x08ac), DVNM("Logitech QuickCam Cool")},
+ {USB_DEVICE(0x046d, 0x08ad), DVNM("Logitech QCCommunicate STX")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x046d, 0x08ae), DVNM("Logitech QuickCam for Notebooks")},
+#endif
+ {USB_DEVICE(0x046d, 0x08af), DVNM("Logitech QuickCam Cool")},
+ {USB_DEVICE(0x046d, 0x08b9), DVNM("Logitech QC IM ???")},
+ {USB_DEVICE(0x046d, 0x08d7), DVNM("Logitech QCam STX")},
+ {USB_DEVICE(0x046d, 0x08d9), DVNM("Logitech QuickCam IM/Connect")},
+ {USB_DEVICE(0x046d, 0x08d8), DVNM("Logitech Notebook Deluxe")},
+ {USB_DEVICE(0x046d, 0x08da), DVNM("Logitech QuickCam Messenger")},
+ {USB_DEVICE(0x046d, 0x08dd), DVNM("Logitech QuickCam for Notebooks")},
+ {USB_DEVICE(0x0471, 0x0325), DVNM("Philips SPC 200 NC")},
+ {USB_DEVICE(0x0471, 0x0326), DVNM("Philips SPC 300 NC")},
+ {USB_DEVICE(0x0471, 0x032d), DVNM("Philips spc210nc")},
+ {USB_DEVICE(0x0471, 0x032e), DVNM("Philips spc315nc")},
+ {USB_DEVICE(0x055f, 0xc005), DVNM("Mustek Wcam300A")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x055f, 0xd003), DVNM("Mustek WCam300A")},
+ {USB_DEVICE(0x055f, 0xd004), DVNM("Mustek WCam300 AN")},
+#endif
+ {USB_DEVICE(0x0698, 0x2003), DVNM("CTX M730V built in")},
+ {USB_DEVICE(0x0ac8, 0x0302), DVNM("Z-star Vimicro zc0302")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x0ac8, 0x301b), DVNM("Z-Star zc301b")},
+ {USB_DEVICE(0x0ac8, 0x303b), DVNM("Vimicro 0x303b")},
+#endif
+ {USB_DEVICE(0x0ac8, 0x305b), DVNM("Z-star Vimicro zc0305b")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x0ac8, 0x307b), DVNM("Z-Star 307b")},
+ {USB_DEVICE(0x10fd, 0x0128), DVNM("Typhoon Webshot II 300k 0x0128")},
+ {USB_DEVICE(0x10fd, 0x8050), DVNM("Typhoon Webshot II USB 300k")},
+#endif
+ {} /* end of entry */
+};
+#undef DVNAME
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+/* USB driver */
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param(force_sensor, int, 0644);
+MODULE_PARM_DESC(force_sensor,
+ "Force sensor. Only for experts!!!");