kernel-ark/drivers/media/video/gspca/sonixj.c
Hans de Goede 3dee4dfed3 V4L/DVB (11221): gspca - sonixj: Prefer sonixj instead of sn9c102 for 0471:0327.
Prefer the gspca sonixj driver for the Philips SPC600NC webcam instead of
the sn9c102 driver. As we've got userreports that it works with the gspca
driver, whereas it fails with the sn9c102 driver, see:
https://bugzilla.redhat.com/show_bug.cgi?id=477111

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2009-03-30 12:43:41 -03:00

2275 lines
66 KiB
C

/*
* 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 V4L2_CID_INFRARED (V4L2_CID_PRIVATE_BASE + 0)
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 */
atomic_t avg_lum;
u32 exposure;
u16 brightness;
u8 contrast;
u8 colors;
u8 autogain;
u8 blue;
u8 red;
u8 gamma;
u8 vflip; /* ov7630/ov7648 only */
u8 infrared; /* mt9v111 only */
u8 quality; /* image quality */
#define QUALITY_MIN 60
#define QUALITY_MAX 95
#define QUALITY_DEF 80
u8 jpegqual; /* webcam quality */
u8 reg18;
s8 ag_cnt;
#define AG_CNT_START 13
u8 bridge;
#define BRIDGE_SN9C102P 0
#define BRIDGE_SN9C105 1
#define BRIDGE_SN9C110 2
#define BRIDGE_SN9C120 3
#define BRIDGE_SN9C325 4
u8 sensor; /* Type of image sensor chip */
#define SENSOR_HV7131R 0
#define SENSOR_MI0360 1
#define SENSOR_MO4000 2
#define SENSOR_MT9V111 3
#define SENSOR_OM6802 4
#define SENSOR_OV7630 5
#define SENSOR_OV7648 6
#define SENSOR_OV7660 7
#define SENSOR_SP80708 8
u8 i2c_base;
u8 *jpeg_hdr;
};
/* 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_setblue_balance(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getred_balance(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_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getinfrared(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 0xffff
.maximum = BRIGHTNESS_MAX,
.step = 1,
#define BRIGHTNESS_DEF 0x8000
.default_value = BRIGHTNESS_DEF,
},
.set = sd_setbrightness,
.get = sd_getbrightness,
},
{
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Contrast",
.minimum = 0,
#define CONTRAST_MAX 127
.maximum = CONTRAST_MAX,
.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 = 40,
.step = 1,
#define COLOR_DEF 32
.default_value = COLOR_DEF,
},
.set = sd_setcolors,
.get = sd_getcolors,
},
{
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Blue Balance",
.minimum = 24,
.maximum = 40,
.step = 1,
#define BLUE_BALANCE_DEF 32
.default_value = BLUE_BALANCE_DEF,
},
.set = sd_setblue_balance,
.get = sd_getblue_balance,
},
{
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Red Balance",
.minimum = 24,
.maximum = 40,
.step = 1,
#define RED_BALANCE_DEF 32
.default_value = RED_BALANCE_DEF,
},
.set = sd_setred_balance,
.get = sd_getred_balance,
},
{
{
.id = V4L2_CID_GAMMA,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gamma",
.minimum = 0,
.maximum = 40,
.step = 1,
#define GAMMA_DEF 20
.default_value = GAMMA_DEF,
},
.set = sd_setgamma,
.get = sd_getgamma,
},
#define AUTOGAIN_IDX 5
{
{
.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,
},
/* ov7630/ov7648 only */
#define VFLIP_IDX 6
{
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Vflip",
.minimum = 0,
.maximum = 1,
.step = 1,
#define VFLIP_DEF 0 /* vflip def = 1 for ov7630 */
.default_value = VFLIP_DEF,
},
.set = sd_setvflip,
.get = sd_getvflip,
},
/* mt9v111 only */
#define INFRARED_IDX 7
{
{
.id = V4L2_CID_INFRARED,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Infrared",
.minimum = 0,
.maximum = 1,
.step = 1,
#define INFRARED_DEF 0
.default_value = INFRARED_DEF,
},
.set = sd_setinfrared,
.get = sd_getinfrared,
},
};
/* table of the disabled controls */
static __u32 ctrl_dis[] = {
(1 << INFRARED_IDX) | (1 << VFLIP_IDX),
/* SENSOR_HV7131R 0 */
(1 << INFRARED_IDX) | (1 << VFLIP_IDX),
/* SENSOR_MI0360 1 */
(1 << INFRARED_IDX) | (1 << VFLIP_IDX),
/* SENSOR_MO4000 2 */
(1 << VFLIP_IDX),
/* SENSOR_MT9V111 3 */
(1 << INFRARED_IDX) | (1 << VFLIP_IDX),
/* SENSOR_OM6802 4 */
(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX),
/* SENSOR_OV7630 5 */
(1 << INFRARED_IDX),
/* SENSOR_OV7648 6 */
(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
/* SENSOR_OV7660 7 */
(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
/* SENSOR_SP80708 8 */
};
static const struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120 * 4 / 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+hv7131r */
static const u8 sn_hv7131[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
0x00, 0x03, 0x64, 0x00, 0x1a, 0x20, 0x20, 0x20,
/* reg8 reg9 rega regb regc regd rege regf */
0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
0x03, 0x00, 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41,
/* reg18 reg19 reg1a reg1b */
0x0a, 0x00, 0x00, 0x00
};
static const u8 sn_mi0360[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20,
/* reg8 reg9 rega regb regc regd rege regf */
0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
0x03, 0x00, 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61,
/* reg18 reg19 reg1a reg1b */
0x06, 0x00, 0x00, 0x00
};
static const u8 sn_mo4000[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
0x00, 0x23, 0x60, 0x00, 0x1a, 0x00, 0x20, 0x18,
/* reg8 reg9 rega regb regc regd rege regf */
0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
0x03, 0x00, 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40,
/* reg18 reg19 reg1a reg1b */
0x08, 0x00, 0x00, 0x00
};
static const u8 sn_mt9v111[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20,
/* reg8 reg9 rega regb regc regd rege regf */
0x81, 0x5c, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
0x03, 0x00, 0x00, 0x02, 0x1c, 0x28, 0x1e, 0x40,
/* reg18 reg19 reg1a reg1b */
0x06, 0x00, 0x00, 0x00
};
static const u8 sn_om6802[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
0x00, 0x23, 0x72, 0x00, 0x1a, 0x34, 0x27, 0x20,
/* reg8 reg9 rega regb regc regd rege regf */
0x80, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
0x03, 0x00, 0x51, 0x01, 0x00, 0x28, 0x1e, 0x40,
/* reg18 reg19 reg1a reg1b */
0x05, 0x00, 0x00, 0x00
};
static const u8 sn_ov7630[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
0x00, 0x21, 0x40, 0x00, 0x1a, 0x20, 0x1f, 0x20,
/* reg8 reg9 rega regb regc regd rege regf */
0xa1, 0x21, 0x76, 0x21, 0x00, 0x00, 0x00, 0x10,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
0x03, 0x00, 0x04, 0x01, 0x0a, 0x28, 0x1e, 0xc2,
/* reg18 reg19 reg1a reg1b */
0x0b, 0x00, 0x00, 0x00
};
static const u8 sn_ov7648[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
0x00, 0x63, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20,
/* reg8 reg9 rega regb regc regd rege regf */
0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
0x03, 0x00, 0x00, 0x01, 0x00, 0x28, 0x1e, 0x00,
/* reg18 reg19 reg1a reg1b */
0x0b, 0x00, 0x00, 0x00
};
static const u8 sn_ov7660[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20,
/* reg8 reg9 rega regb regc regd rege regf */
0x81, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
0x03, 0x00, 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20,
/* reg18 reg19 reg1a reg1b */
0x07, 0x00, 0x00, 0x00
};
static const u8 sn_sp80708[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
0x00, 0x63, 0x60, 0x00, 0x1a, 0x20, 0x20, 0x20,
/* reg8 reg9 rega regb regc regd rege regf */
0x81, 0x18, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
0x03, 0x00, 0x00, 0x03, 0x04, 0x28, 0x1e, 0x00,
/* reg18 reg19 reg1a reg1b */
0x07, 0x00, 0x00, 0x00
};
/* sequence specific to the sensors - !! index = SENSOR_xxx */
static const u8 *sn_tb[] = {
sn_hv7131,
sn_mi0360,
sn_mo4000,
sn_mt9v111,
sn_om6802,
sn_ov7630,
sn_ov7648,
sn_ov7660,
sn_sp80708
};
/* default gamma table */
static const u8 gamma_def[17] = {
0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
};
/* gamma for sensors HV7131R and MT9V111 */
static const u8 gamma_spec_1[17] = {
0x08, 0x3a, 0x52, 0x65, 0x75, 0x83, 0x91, 0x9d,
0xa9, 0xb4, 0xbe, 0xc8, 0xd2, 0xdb, 0xe4, 0xed, 0xf5
};
/* gamma for sensor SP80708 */
static const u8 gamma_spec_2[17] = {
0x0a, 0x2d, 0x4e, 0x68, 0x7d, 0x8f, 0x9f, 0xab,
0xb7, 0xc2, 0xcc, 0xd3, 0xd8, 0xde, 0xe2, 0xe5, 0xe6
};
/* color matrix and offsets */
static const u8 reg84[] = {
0x14, 0x00, 0x27, 0x00, 0x07, 0x00, /* YR YG YB gains */
0xe8, 0x0f, 0xda, 0x0f, 0x40, 0x00, /* UR UG UB */
0x3e, 0x00, 0xcd, 0x0f, 0xf7, 0x0f, /* VR VG VB */
0x00, 0x00, 0x00 /* YUV offsets */
};
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 mt9v111_sensor_init[][8] = {
{0xb1, 0x5c, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10}, /* reset? */
/* delay 20 ms */
{0xb1, 0x5c, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x01, 0x00, 0x01, 0x00, 0x00, 0x10}, /* IFP select */
{0xb1, 0x5c, 0x08, 0x04, 0x80, 0x00, 0x00, 0x10}, /* output fmt ctrl */
{0xb1, 0x5c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}, /* op mode ctrl */
{0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x03, 0x01, 0xe1, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x04, 0x02, 0x81, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x05, 0x00, 0x04, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10}, /* sensor select */
{0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x03, 0x01, 0xe6, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x04, 0x02, 0x86, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x05, 0x00, 0x04, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x08, 0x00, 0x08, 0x00, 0x00, 0x10}, /* row start */
{0xb1, 0x5c, 0x0e, 0x00, 0x08, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10}, /* col start */
{0xb1, 0x5c, 0x03, 0x01, 0xe7, 0x00, 0x00, 0x10}, /* window height */
{0xb1, 0x5c, 0x04, 0x02, 0x87, 0x00, 0x00, 0x10}, /* window width */
{0xb1, 0x5c, 0x07, 0x30, 0x02, 0x00, 0x00, 0x10}, /* output ctrl */
{0xb1, 0x5c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10}, /* shutter delay */
{0xb1, 0x5c, 0x12, 0x00, 0xb0, 0x00, 0x00, 0x10}, /* zoom col start */
{0xb1, 0x5c, 0x13, 0x00, 0x7c, 0x00, 0x00, 0x10}, /* zoom row start */
{0xb1, 0x5c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x10}, /* digital zoom */
{0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, /* read mode */
{0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
/*******/
{0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x09, 0x01, 0x2c, 0x00, 0x00, 0x10},
{0xd1, 0x5c, 0x2b, 0x00, 0x33, 0x00, 0xa0, 0x10}, /* green1 gain */
{0xd1, 0x5c, 0x2d, 0x00, 0xa0, 0x00, 0x33, 0x10}, /* red gain */
/*******/
{0xb1, 0x5c, 0x06, 0x00, 0x1e, 0x00, 0x00, 0x10}, /* vert blanking */
{0xb1, 0x5c, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x10}, /* horiz blanking */
{0xd1, 0x5c, 0x2c, 0x00, 0xad, 0x00, 0xad, 0x10}, /* blue gain */
{0xb1, 0x5c, 0x35, 0x01, 0xc0, 0x00, 0x00, 0x10}, /* global gain */
{}
};
static const u8 om6802_sensor_init[][8] = {
{0xa0, 0x34, 0x90, 0x05, 0x00, 0x00, 0x00, 0x10},
{0xa0, 0x34, 0x49, 0x85, 0x00, 0x00, 0x00, 0x10},
{0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10},
{0xa0, 0x34, 0xdd, 0x18, 0x00, 0x00, 0x00, 0x10},
/* {0xa0, 0x34, 0xfb, 0x11, 0x00, 0x00, 0x00, 0x10}, */
{0xa0, 0x34, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x10},
/* white balance & auto-exposure */
/* {0xa0, 0x34, 0xf1, 0x02, 0x00, 0x00, 0x00, 0x10},
* set color mode */
/* {0xa0, 0x34, 0xfe, 0x5b, 0x00, 0x00, 0x00, 0x10},
* max AGC value in AE */
/* {0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10},
* preset AGC */
/* {0xa0, 0x34, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x10},
* preset brightness */
/* {0xa0, 0x34, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10},
* preset contrast */
/* {0xa0, 0x34, 0xe8, 0x31, 0x00, 0x00, 0x00, 0x10},
* preset gamma */
{0xa0, 0x34, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x10},
/* luminance mode (0x4f = AE) */
{0xa0, 0x34, 0xe4, 0xff, 0x00, 0x00, 0x00, 0x10},
/* preset shutter */
/* {0xa0, 0x34, 0xef, 0x00, 0x00, 0x00, 0x00, 0x10},
* auto frame rate */
/* {0xa0, 0x34, 0xfb, 0xee, 0x00, 0x00, 0x00, 0x10}, */
/* {0xa0, 0x34, 0x71, 0x84, 0x00, 0x00, 0x00, 0x10}, */
/* {0xa0, 0x34, 0x72, 0x05, 0x00, 0x00, 0x00, 0x10}, */
/* {0xa0, 0x34, 0x68, 0x80, 0x00, 0x00, 0x00, 0x10}, */
/* {0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, */
{}
};
static const u8 ov7630_sensor_init[][8] = {
{0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
/* win: delay 20ms */
{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
/* win: delay 20ms */
{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
/* win: i2c_r from 00 to 80 */
{0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10},
{0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10},
{0xd1, 0x21, 0x11, 0x00, 0x48, 0xc0, 0x00, 0x10},
{0xb1, 0x21, 0x15, 0x80, 0x03, 0x00, 0x00, 0x10},
{0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10},
{0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
{0xd1, 0x21, 0x1f, 0x00, 0x80, 0x80, 0x80, 0x10},
{0xd1, 0x21, 0x23, 0xde, 0x10, 0x8a, 0xa0, 0x10},
{0xc1, 0x21, 0x27, 0xca, 0xa2, 0x74, 0x00, 0x10},
{0xd1, 0x21, 0x2a, 0x88, 0x00, 0x88, 0x01, 0x10},
{0xc1, 0x21, 0x2e, 0x80, 0x00, 0x18, 0x00, 0x10},
{0xa1, 0x21, 0x21, 0x08, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xb1, 0x21, 0x32, 0xc2, 0x08, 0x00, 0x00, 0x10},
{0xb1, 0x21, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xd1, 0x21, 0x60, 0x05, 0x40, 0x12, 0x57, 0x10},
{0xa1, 0x21, 0x64, 0x73, 0x00, 0x00, 0x00, 0x10},
{0xd1, 0x21, 0x65, 0x00, 0x55, 0x01, 0xac, 0x10},
{0xa1, 0x21, 0x69, 0x38, 0x00, 0x00, 0x00, 0x10},
{0xd1, 0x21, 0x6f, 0x1f, 0x01, 0x00, 0x10, 0x10},
{0xd1, 0x21, 0x73, 0x50, 0x20, 0x02, 0x01, 0x10},
{0xd1, 0x21, 0x77, 0xf3, 0x90, 0x98, 0x98, 0x10},
{0xc1, 0x21, 0x7b, 0x00, 0x4c, 0xf7, 0x00, 0x10},
{0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10},
{0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
/* */
{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
/*fixme: + 0x12, 0x04*/
/* {0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10}, * COMN
* set by setvflip */
{0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10},
/* */
{0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10},
/* */
{0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10},
/* {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */
{}
};
static const u8 ov7648_sensor_init[][8] = {
{0xa1, 0x21, 0x76, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset */
{0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xd1, 0x21, 0x03, 0xa4, 0x30, 0x88, 0x00, 0x10},
{0xb1, 0x21, 0x11, 0x80, 0x08, 0x00, 0x00, 0x10},
{0xc1, 0x21, 0x13, 0xa0, 0x04, 0x84, 0x00, 0x10},
{0xd1, 0x21, 0x17, 0x1a, 0x02, 0xba, 0xf4, 0x10},
{0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
{0xd1, 0x21, 0x1f, 0x41, 0xc0, 0x80, 0x80, 0x10},
{0xd1, 0x21, 0x23, 0xde, 0xa0, 0x80, 0x32, 0x10},
{0xd1, 0x21, 0x27, 0xfe, 0xa0, 0x00, 0x91, 0x10},
{0xd1, 0x21, 0x2b, 0x00, 0x88, 0x85, 0x80, 0x10},
{0xc1, 0x21, 0x2f, 0x9c, 0x00, 0xc4, 0x00, 0x10},
{0xd1, 0x21, 0x60, 0xa6, 0x60, 0x88, 0x12, 0x10},
{0xd1, 0x21, 0x64, 0x88, 0x00, 0x00, 0x94, 0x10},
{0xd1, 0x21, 0x68, 0x7a, 0x0c, 0x00, 0x00, 0x10},
{0xd1, 0x21, 0x6c, 0x11, 0x33, 0x22, 0x00, 0x10},
{0xd1, 0x21, 0x70, 0x11, 0x00, 0x10, 0x50, 0x10},
{0xd1, 0x21, 0x74, 0x20, 0x06, 0x00, 0xb5, 0x10},
{0xd1, 0x21, 0x78, 0x8a, 0x00, 0x00, 0x00, 0x10},
{0xb1, 0x21, 0x7c, 0x00, 0x43, 0x00, 0x00, 0x10},
{0xd1, 0x21, 0x21, 0x86, 0x00, 0xde, 0xa0, 0x10},
/* {0xd1, 0x21, 0x25, 0x80, 0x32, 0xfe, 0xa0, 0x10}, jfm done */
/* {0xd1, 0x21, 0x29, 0x00, 0x91, 0x00, 0x88, 0x10}, jfm done */
{0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10},
/*...*/
/* {0xa1, 0x21, 0x12, 0x08, 0x00, 0x00, 0x00, 0x10}, jfm done */
/* {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10}, * COMN
* set by setvflip */
{0xa1, 0x21, 0x19, 0x02, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10},
/* {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */
/* {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, * GAIN - def */
/* {0xb1, 0x21, 0x01, 0x6c, 0x6c, 0x00, 0x00, 0x10}, * B R - def: 80 */
/*...*/
{0xa1, 0x21, 0x11, 0x81, 0x00, 0x00, 0x00, 0x10}, /* CLKRC */
/* {0xa1, 0x21, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */
/* {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */
/* {0xa1, 0x21, 0x2a, 0x91, 0x00, 0x00, 0x00, 0x10}, jfm done */
/* {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */
/* {0xb1, 0x21, 0x01, 0x64, 0x84, 0x00, 0x00, 0x10}, * B R - def: 80 */
{}
};
static const u8 ov7660_sensor_init[][8] = {
{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
/* (delay 20ms) */
{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, 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, 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}, /* MANU */
{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}, /* DM_LNL/H */
/****** (some exchanges in the win trace) ******/
{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */
/* 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}, /* AECH 0x20 */
{0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFL */
{0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFH */
{0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, /* GAIN */
/* {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, * BLUE */
/****** (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}, /* EXHCH */
{0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCL */
/* {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, * RED */
/****** (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},
{}
};
static const u8 sp80708_sensor_init[][8] = {
{0xa1, 0x18, 0x06, 0xf9, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x09, 0x1f, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x0d, 0xc0, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x10, 0x40, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x11, 0x4e, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x12, 0x53, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x15, 0x80, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x19, 0x18, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x1a, 0x10, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x1c, 0x28, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x1d, 0x02, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x1e, 0x10, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x26, 0x04, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x27, 0x1e, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x28, 0x5a, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x29, 0x28, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x2a, 0x78, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x2c, 0xf7, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x2d, 0x2d, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x2e, 0xd5, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x39, 0x42, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x3a, 0x67, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x3b, 0x87, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x3c, 0xa3, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x3d, 0xb0, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x3e, 0xbc, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x3f, 0xc8, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x40, 0xd4, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x41, 0xdf, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x42, 0xea, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x43, 0xf5, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x45, 0x80, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x46, 0x60, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x47, 0x50, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x48, 0x30, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x49, 0x01, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x4d, 0xae, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x4e, 0x03, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x4f, 0x66, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x50, 0x1c, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x44, 0x10, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x4a, 0x30, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x51, 0x80, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x52, 0x80, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x53, 0x80, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x54, 0x80, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x55, 0x80, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x56, 0x80, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x57, 0xe0, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x58, 0xc0, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x59, 0xab, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x5a, 0xa0, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x5b, 0x99, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x5c, 0x90, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x5e, 0x24, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x61, 0x73, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x63, 0x42, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x64, 0x42, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x65, 0x42, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x66, 0x24, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x67, 0x24, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x68, 0x08, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x2f, 0xc9, 0x00, 0x00, 0x00, 0x10},
/********/
{0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x03, 0x01, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x04, 0xa4, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x14, 0x3f, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x18, 0x5d, 0x80, 0x00, 0x00, 0x00, 0x10},
{0xb1, 0x18, 0x11, 0x40, 0x40, 0x00, 0x00, 0x10},
{}
};
/* read <len> bytes to gspca_dev->usb_buf */
static void reg_r(struct gspca_dev *gspca_dev,
u16 value, int len)
{
#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
err("reg_r: buffer overflow");
return;
}
#endif
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);
PDEBUG(D_USBI, "reg_r [%02x] -> %02x", value, gspca_dev->usb_buf[0]);
}
static void reg_w1(struct gspca_dev *gspca_dev,
u16 value,
u8 data)
{
PDEBUG(D_USBO, "reg_w1 [%04x] = %02x", value, data);
gspca_dev->usb_buf[0] = data;
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, 1,
500);
}
static void reg_w(struct gspca_dev *gspca_dev,
u16 value,
const u8 *buffer,
int len)
{
PDEBUG(D_USBO, "reg_w [%04x] = %02x %02x ..",
value, buffer[0], buffer[1]);
#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
err("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,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
value, 0,
gspca_dev->usb_buf, len,
500);
}
/* I2C write 1 byte */
static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
{
struct sd *sd = (struct sd *) gspca_dev;
PDEBUG(D_USBO, "i2c_w2 [%02x] = %02x", reg, val);
gspca_dev->usb_buf[0] = 0x81 | (2 << 4); /* = a1 */
gspca_dev->usb_buf[1] = sd->i2c_base;
gspca_dev->usb_buf[2] = reg;
gspca_dev->usb_buf[3] = val;
gspca_dev->usb_buf[4] = 0;
gspca_dev->usb_buf[5] = 0;
gspca_dev->usb_buf[6] = 0;
gspca_dev->usb_buf[7] = 0x10;
usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0x08,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
0x08, /* value = i2c */
0,
gspca_dev->usb_buf, 8,
500);
}
/* I2C write 8 bytes */
static void i2c_w8(struct gspca_dev *gspca_dev,
const u8 *buffer)
{
memcpy(gspca_dev->usb_buf, buffer, 8);
usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0x08,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
0x08, 0, /* value, index */
gspca_dev->usb_buf, 8,
500);
msleep(2);
}
/* 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);
msleep(2);
mode[0] = 0x81 | (5 << 4) | 0x02;
mode[2] = 0;
i2c_w8(gspca_dev, mode);
msleep(2);
reg_r(gspca_dev, 0x0a, 5);
}
static int hv7131r_probe(struct gspca_dev *gspca_dev)
{
i2c_w1(gspca_dev, 0x02, 0); /* sensor wakeup */
msleep(10);
reg_w1(gspca_dev, 0x02, 0x66); /* 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");
return 0;
}
PDEBUG(D_PROBE, "Find Sensor 0x%02x 0x%02x 0x%02x",
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 void mi0360_probe(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i, j;
u16 val = 0;
static const u8 probe_tb[][4][8] = {
{ /* mi0360 */
{0xb0, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
{0x90, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa2, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xb0, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10}
},
{ /* mt9v111 */
{0xb0, 0x5c, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10},
{0x90, 0x5c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa2, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
{}
},
};
for (i = 0; i < ARRAY_SIZE(probe_tb); i++) {
reg_w1(gspca_dev, 0x17, 0x62);
reg_w1(gspca_dev, 0x01, 0x08);
for (j = 0; j < 3; j++)
i2c_w8(gspca_dev, probe_tb[i][j]);
msleep(2);
reg_r(gspca_dev, 0x0a, 5);
val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
if (probe_tb[i][3][0] != 0)
i2c_w8(gspca_dev, probe_tb[i][3]);
reg_w1(gspca_dev, 0x01, 0x29);
reg_w1(gspca_dev, 0x17, 0x42);
if (val != 0xffff)
break;
}
switch (val) {
case 0x823a:
PDEBUG(D_PROBE, "Sensor mt9v111");
sd->sensor = SENSOR_MT9V111;
sd->i2c_base = 0x5c;
break;
case 0x8243:
PDEBUG(D_PROBE, "Sensor mi0360");
break;
default:
PDEBUG(D_PROBE, "Unknown sensor %04x - forced to mi0360", val);
break;
}
}
static int configure_gpio(struct gspca_dev *gspca_dev,
const u8 *sn9c1xx)
{
struct sd *sd = (struct sd *) gspca_dev;
const u8 *reg9a;
static const u8 reg9a_def[] =
{0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
static const u8 reg9a_sn9c325[] =
{0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
static const u8 regd4[] = {0x60, 0x00, 0x00};
reg_w1(gspca_dev, 0xf1, 0x00);
reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
/* 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 len was 3 */
switch (sd->bridge) {
case BRIDGE_SN9C325:
reg9a = reg9a_sn9c325;
break;
default:
reg9a = reg9a_def;
break;
}
reg_w(gspca_dev, 0x9a, reg9a, 6);
reg_w(gspca_dev, 0xd4, regd4, sizeof regd4); /*fixme:jfm was 60 only*/
reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
switch (sd->sensor) {
case SENSOR_MT9V111:
reg_w1(gspca_dev, 0x01, 0x61);
reg_w1(gspca_dev, 0x17, 0x61);
reg_w1(gspca_dev, 0x01, 0x60);
reg_w1(gspca_dev, 0x01, 0x40);
break;
case SENSOR_OM6802:
reg_w1(gspca_dev, 0x02, 0x71);
reg_w1(gspca_dev, 0x01, 0x42);
reg_w1(gspca_dev, 0x17, 0x64);
reg_w1(gspca_dev, 0x01, 0x42);
break;
/*jfm: from win trace */
case SENSOR_OV7630:
reg_w1(gspca_dev, 0x01, 0x61);
reg_w1(gspca_dev, 0x17, 0xe2);
reg_w1(gspca_dev, 0x01, 0x60);
reg_w1(gspca_dev, 0x01, 0x40);
break;
case SENSOR_OV7648:
reg_w1(gspca_dev, 0x01, 0x63);
reg_w1(gspca_dev, 0x17, 0x20);
reg_w1(gspca_dev, 0x01, 0x42);
break;
/*jfm: from win trace */
case SENSOR_OV7660:
if (sd->bridge == BRIDGE_SN9C120) {
reg_w1(gspca_dev, 0x01, 0x61);
reg_w1(gspca_dev, 0x17, 0x20);
reg_w1(gspca_dev, 0x01, 0x60);
reg_w1(gspca_dev, 0x01, 0x40);
break;
}
/* fall thru */
case SENSOR_SP80708:
reg_w1(gspca_dev, 0x01, 0x63);
reg_w1(gspca_dev, 0x17, 0x20);
reg_w1(gspca_dev, 0x01, 0x62);
reg_w1(gspca_dev, 0x01, 0x42);
mdelay(100);
reg_w1(gspca_dev, 0x02, 0x62);
break;
default:
reg_w1(gspca_dev, 0x01, 0x43);
reg_w1(gspca_dev, 0x17, 0x61);
reg_w1(gspca_dev, 0x01, 0x42);
if (sd->sensor == SENSOR_HV7131R) {
if (hv7131r_probe(gspca_dev) < 0)
return -ENODEV;
}
break;
}
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 mt9v111_InitSensor(struct gspca_dev *gspca_dev)
{
int i = 0;
i2c_w8(gspca_dev, mt9v111_sensor_init[i]);
i++;
msleep(20);
while (mt9v111_sensor_init[i][0]) {
i2c_w8(gspca_dev, mt9v111_sensor_init[i]);
i++;
}
}
static void om6802_InitSensor(struct gspca_dev *gspca_dev)
{
int i = 0;
while (om6802_sensor_init[i][0]) {
i2c_w8(gspca_dev, om6802_sensor_init[i]);
i++;
}
}
static void ov7630_InitSensor(struct gspca_dev *gspca_dev)
{
int i = 0;
i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 76 01 */
i++;
i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 c8 (RGB+SRST) */
i++;
msleep(20);
i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 48 */
i++;
i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 c8 */
i++;
msleep(20);
i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 48 */
i++;
/*jfm:win i2c_r from 00 to 80*/
while (ov7630_sensor_init[i][0]) {
i2c_w8(gspca_dev, ov7630_sensor_init[i]);
i++;
}
}
static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
{
int i = 0;
i2c_w8(gspca_dev, ov7648_sensor_init[i]);
i++;
/* win: dble reset */
i2c_w8(gspca_dev, ov7648_sensor_init[i]); /* reset */
i++;
msleep(20);
/* win: i2c reg read 00..7f */
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;
i2c_w8(gspca_dev, ov7660_sensor_init[i]); /* reset SCCB */
i++;
msleep(20);
while (ov7660_sensor_init[i][0]) {
i2c_w8(gspca_dev, ov7660_sensor_init[i]);
i++;
}
}
static void sp80708_InitSensor(struct gspca_dev *gspca_dev)
{
int i = 0;
i2c_w8(gspca_dev, sp80708_sensor_init[i]); /* reset SCCB */
i++;
msleep(20);
while (sp80708_sensor_init[i][0]) {
i2c_w8(gspca_dev, sp80708_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;
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
sd->bridge = id->driver_info >> 16;
sd->sensor = id->driver_info >> 8;
sd->i2c_base = id->driver_info;
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
sd->blue = BLUE_BALANCE_DEF;
sd->red = RED_BALANCE_DEF;
sd->gamma = GAMMA_DEF;
sd->autogain = AUTOGAIN_DEF;
sd->ag_cnt = -1;
if (sd->sensor != SENSOR_OV7630)
sd->vflip = 0;
else
sd->vflip = 1;
sd->infrared = INFRARED_DEF;
sd->quality = QUALITY_DEF;
sd->jpegqual = 80;
gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
return 0;
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 regGpio[] = { 0x29, 0x74 };
u8 regF1;
/* setup a selector by bridge */
reg_w1(gspca_dev, 0xf1, 0x01);
reg_r(gspca_dev, 0x00, 1);
reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]);
reg_r(gspca_dev, 0x00, 1); /* get sonix chip id */
regF1 = gspca_dev->usb_buf[0];
PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1);
switch (sd->bridge) {
case BRIDGE_SN9C102P:
if (regF1 != 0x11)
return -ENODEV;
reg_w1(gspca_dev, 0x02, regGpio[1]);
break;
case BRIDGE_SN9C105:
if (regF1 != 0x11)
return -ENODEV;
if (sd->sensor == SENSOR_MI0360)
mi0360_probe(gspca_dev);
reg_w(gspca_dev, 0x01, regGpio, 2);
break;
case BRIDGE_SN9C120:
if (regF1 != 0x12)
return -ENODEV;
if (sd->sensor == SENSOR_MI0360)
mi0360_probe(gspca_dev);
regGpio[1] = 0x70;
reg_w(gspca_dev, 0x01, regGpio, 2);
break;
default:
/* case BRIDGE_SN9C110: */
/* case BRIDGE_SN9C325: */
if (regF1 != 0x12)
return -ENODEV;
reg_w1(gspca_dev, 0x02, 0x62);
break;
}
reg_w1(gspca_dev, 0xf1, 0x01);
return 0;
}
static u32 setexposure(struct gspca_dev *gspca_dev,
u32 expo)
{
struct sd *sd = (struct sd *) gspca_dev;
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 };
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 };
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 };
static const u8 gainMo[] =
{ 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
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_FRAM, "set exposure %d",
((expoMo10[3] & 0x07) << 10)
| (expoMof[3] << 2)
| ((expoMo10[3] & 0x30) >> 4));
break;
}
case SENSOR_MT9V111: {
u8 expo_c1[] =
{ 0xb1, 0x5c, 0x09, 0x00, 0x00, 0x00, 0x00, 0x10 };
if (expo > 0x0280)
expo = 0x0280;
else if (expo < 0x0040)
expo = 0x0040;
expo_c1[3] = expo >> 8;
expo_c1[4] = expo;
i2c_w8(gspca_dev, expo_c1);
break;
}
case SENSOR_OM6802: {
u8 gainOm[] =
{ 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 };
if (expo > 0x03ff)
expo = 0x03ff;
if (expo < 0x0001)
expo = 0x0001;
gainOm[3] = expo >> 2;
i2c_w8(gspca_dev, gainOm);
reg_w1(gspca_dev, 0x96, (expo >> 5) & 0x1f);
PDEBUG(D_FRAM, "set exposure %d", gainOm[3]);
break;
}
}
return expo;
}
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
unsigned int expo;
u8 k2;
k2 = ((int) sd->brightness - 0x8000) >> 10;
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:
case SENSOR_MO4000:
expo = sd->brightness >> 4;
sd->exposure = setexposure(gspca_dev, expo);
break;
case SENSOR_MT9V111:
expo = sd->brightness >> 8;
sd->exposure = setexposure(gspca_dev, expo);
break;
case SENSOR_OM6802:
expo = sd->brightness >> 6;
sd->exposure = setexposure(gspca_dev, expo);
k2 = sd->brightness >> 11;
break;
}
if (sd->sensor != SENSOR_MT9V111)
reg_w1(gspca_dev, 0x96, k2); /* color matrix Y offset */
}
static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 k2;
u8 contrast[6];
k2 = sd->contrast * 0x30 / (CONTRAST_MAX + 1) + 0x10; /* 10..40 */
contrast[0] = (k2 + 1) / 2; /* red */
contrast[1] = 0;
contrast[2] = k2; /* green */
contrast[3] = 0;
contrast[4] = (k2 + 1) / 5; /* blue */
contrast[5] = 0;
reg_w(gspca_dev, 0x84, contrast, sizeof contrast);
}
static void setcolors(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i, v;
u8 reg8a[12]; /* U & V gains */
static s16 uv[6] = { /* same as reg84 in signed decimal */
-24, -38, 64, /* UR UG UB */
62, -51, -9 /* VR VG VB */
};
for (i = 0; i < 6; i++) {
v = uv[i] * sd->colors / COLOR_DEF;
reg8a[i * 2] = v;
reg8a[i * 2 + 1] = (v >> 8) & 0x0f;
}
reg_w(gspca_dev, 0x8a, reg8a, sizeof reg8a);
}
static void setredblue(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
reg_w1(gspca_dev, 0x05, sd->red);
/* reg_w1(gspca_dev, 0x07, 32); */
reg_w1(gspca_dev, 0x06, sd->blue);
}
static void setgamma(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
u8 gamma[17];
const u8 *gamma_base;
static const u8 delta[17] = {
0x00, 0x14, 0x1c, 0x1c, 0x1c, 0x1c, 0x1b, 0x1a,
0x18, 0x13, 0x10, 0x0e, 0x08, 0x07, 0x04, 0x02, 0x00
};
switch (sd->sensor) {
case SENSOR_HV7131R:
case SENSOR_MT9V111:
gamma_base = gamma_spec_1;
break;
case SENSOR_SP80708:
gamma_base = gamma_spec_2;
break;
default:
gamma_base = gamma_def;
break;
}
for (i = 0; i < sizeof gamma; i++)
gamma[i] = gamma_base[i]
+ delta[i] * (sd->gamma - GAMMA_DEF) / 32;
reg_w(gspca_dev, 0x20, gamma, sizeof gamma);
}
static void setautogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
return;
switch (sd->sensor) {
case SENSOR_OV7630:
case SENSOR_OV7648: {
u8 comb;
if (sd->sensor == SENSOR_OV7630)
comb = 0xc0;
else
comb = 0xa0;
if (sd->autogain)
comb |= 0x02;
i2c_w1(&sd->gspca_dev, 0x13, comb);
return;
}
}
if (sd->autogain)
sd->ag_cnt = AG_CNT_START;
else
sd->ag_cnt = -1;
}
/* ov7630/ov7648 only */
static void setvflip(struct sd *sd)
{
u8 comn;
if (sd->sensor == SENSOR_OV7630)
comn = 0x02;
else
comn = 0x06;
if (sd->vflip)
comn |= 0x80;
i2c_w1(&sd->gspca_dev, 0x75, comn);
}
static void setinfrared(struct sd *sd)
{
/*fixme: different sequence for StarCam Clip and StarCam 370i */
/* Clip */
i2c_w1(&sd->gspca_dev, 0x02, /* gpio */
sd->infrared ? 0x66 : 0x64);
}
static void setjpegqual(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i, sc;
if (sd->jpegqual < 50)
sc = 5000 / sd->jpegqual;
else
sc = 200 - sd->jpegqual * 2;
#if USB_BUF_SZ < 64
#error "No room enough in usb_buf for quantization table"
#endif
for (i = 0; i < 64; i++)
gspca_dev->usb_buf[i] =
(jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100;
usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0x08,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
0x0100, 0,
gspca_dev->usb_buf, 64,
500);
for (i = 0; i < 64; i++)
gspca_dev->usb_buf[i] =
(jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100;
usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0x08,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
0x0140, 0,
gspca_dev->usb_buf, 64,
500);
sd->reg18 ^= 0x40;
reg_w1(gspca_dev, 0x18, sd->reg18);
}
/* -- start the camera -- */
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
u8 reg1, reg17;
const u8 *sn9c1xx;
int mode;
static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
static const u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */
static const u8 CE_ov76xx[] =
{ 0x32, 0xdd, 0x32, 0xdd };
/* create the JPEG header */
sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
sn9c1xx = sn_tb[(int) sd->sensor];
configure_gpio(gspca_dev, sn9c1xx);
reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]);
reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]);
reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]);
reg_w1(gspca_dev, 0x13, sn9c1xx[0x13]);
reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
reg_w1(gspca_dev, 0xd2, 0x6a); /* DC29 */
reg_w1(gspca_dev, 0xd3, 0x50);
reg_w1(gspca_dev, 0xc6, 0x00);
reg_w1(gspca_dev, 0xc7, 0x00);
reg_w1(gspca_dev, 0xc8, 0x50);
reg_w1(gspca_dev, 0xc9, 0x3c);
reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
switch (sd->sensor) {
case SENSOR_MT9V111:
reg17 = 0xe0;
break;
case SENSOR_OV7630:
reg17 = 0xe2;
break;
case SENSOR_OV7648:
reg17 = 0x20;
break;
/*jfm: from win trace */
case SENSOR_OV7660:
if (sd->bridge == BRIDGE_SN9C120) {
reg17 = 0xa0;
break;
}
/* fall thru */
default:
reg17 = 0x60;
break;
}
reg_w1(gspca_dev, 0x17, reg17);
/* set reg1 was here */
reg_w1(gspca_dev, 0x05, sn9c1xx[5]); /* red */
reg_w1(gspca_dev, 0x07, sn9c1xx[7]); /* green */
reg_w1(gspca_dev, 0x06, sn9c1xx[6]); /* blue */
reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]);
setgamma(gspca_dev);
for (i = 0; i < 8; i++)
reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
switch (sd->sensor) {
case SENSOR_MT9V111:
reg_w1(gspca_dev, 0x9a, 0x07);
reg_w1(gspca_dev, 0x99, 0x59);
break;
case SENSOR_OV7648:
reg_w1(gspca_dev, 0x9a, 0x0a);
reg_w1(gspca_dev, 0x99, 0x60);
break;
case SENSOR_SP80708:
reg_w1(gspca_dev, 0x9a, 0x05);
reg_w1(gspca_dev, 0x99, 0x59);
break;
case SENSOR_OV7660:
if (sd->bridge == BRIDGE_SN9C120) {
reg_w1(gspca_dev, 0x9a, 0x05);
break;
}
/* fall thru */
default:
reg_w1(gspca_dev, 0x9a, 0x08);
reg_w1(gspca_dev, 0x99, 0x59);
break;
}
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
if (mode)
reg1 = 0x46; /* 320x240: clk 48Mhz, video trf enable */
else
reg1 = 0x06; /* 640x480: clk 24Mhz, video trf enable */
reg17 = 0x61; /* 0x:20: enable sensor clock */
switch (sd->sensor) {
case SENSOR_HV7131R:
hv7131R_InitSensor(gspca_dev);
break;
case SENSOR_MI0360:
mi0360_InitSensor(gspca_dev);
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 (done) */
}
break;
case SENSOR_MT9V111:
mt9v111_InitSensor(gspca_dev);
if (mode) {
reg1 = 0x04; /* 320 clk 48Mhz */
} else {
/* reg1 = 0x06; * 640 clk 24Mz (done) */
reg17 = 0xc2;
}
break;
case SENSOR_OM6802:
om6802_InitSensor(gspca_dev);
reg17 = 0x64; /* 640 MCKSIZE */
break;
case SENSOR_OV7630:
ov7630_InitSensor(gspca_dev);
setvflip(sd);
reg17 = 0xe2;
reg1 = 0x44;
break;
case SENSOR_OV7648:
ov7648_InitSensor(gspca_dev);
reg17 = 0x21;
/* reg1 = 0x42; * 42 - 46? */
break;
case SENSOR_OV7660:
ov7660_InitSensor(gspca_dev);
if (sd->bridge == BRIDGE_SN9C120) {
if (mode) { /* 320x240 - 160x120 */
reg17 = 0xa2;
reg1 = 0x44; /* 48 Mhz, video trf eneble */
}
} else {
reg17 = 0x22;
reg1 = 0x06; /* 24 Mhz, video trf eneble
* inverse power down */
}
break;
default:
/* case SENSOR_SP80708: */
sp80708_InitSensor(gspca_dev);
if (mode) {
/*?? reg1 = 0x04; * 320 clk 48Mhz */
} else {
reg1 = 0x46; /* 640 clk 48Mz */
reg17 = 0xa2;
}
break;
}
reg_w(gspca_dev, 0xc0, C0, 6);
reg_w(gspca_dev, 0xca, CA, 4);
switch (sd->sensor) {
case SENSOR_OV7630:
case SENSOR_OV7648:
case SENSOR_OV7660:
reg_w(gspca_dev, 0xce, CE_ov76xx, 4);
break;
default:
reg_w(gspca_dev, 0xce, CE, 4);
/* ?? {0x1e, 0xdd, 0x2d, 0xe7} */
break;
}
/* here change size mode 0 -> VGA; 1 -> CIF */
sd->reg18 = sn9c1xx[0x18] | (mode << 4) | 0x40;
reg_w1(gspca_dev, 0x18, sd->reg18);
setjpegqual(gspca_dev);
reg_w1(gspca_dev, 0x17, reg17);
reg_w1(gspca_dev, 0x01, reg1);
switch (sd->sensor) {
case SENSOR_OV7630:
setvflip(sd);
break;
}
setbrightness(gspca_dev);
setcontrast(gspca_dev);
setautogain(gspca_dev);
return 0;
}
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 };
static const u8 stopov7648[] =
{ 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 };
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_OV7648:
i2c_w8(gspca_dev, stopov7648);
/* fall thru */
case SENSOR_MT9V111:
case SENSOR_OV7630:
data = 0x29;
break;
default:
/* case SENSOR_MO4000: */
/* case SENSOR_OV7660: */
break;
}
sn9c1xx = sn_tb[(int) sd->sensor];
reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]);
reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
reg_w1(gspca_dev, 0x01, data);
reg_w1(gspca_dev, 0xf1, 0x00);
}
static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
kfree(sd->jpeg_hdr);
}
static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int delta;
int expotimes;
u8 luma_mean = 130;
u8 luma_delta = 20;
/* Thanks S., without your advice, autobright should not work :) */
if (sd->ag_cnt < 0)
return;
if (--sd->ag_cnt >= 0)
return;
sd->ag_cnt = AG_CNT_START;
delta = atomic_read(&sd->avg_lum);
PDEBUG(D_FRAM, "mean lum %d", delta);
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;
default:
/* case SENSOR_MO4000: */
/* case SENSOR_MI0360: */
/* case SENSOR_MT9V111: */
/* case SENSOR_OM6802: */
expotimes = sd->exposure;
expotimes += (luma_mean - delta) >> 6;
if (expotimes < 0)
expotimes = 0;
sd->exposure = setexposure(gspca_dev,
(unsigned int) expotimes);
setredblue(gspca_dev);
break;
}
}
}
/* scan the URB packets */
/* This function is run at interrupt level. */
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;
/* 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;
atomic_set(&sd->avg_lum, avg_lum);
return;
}
if (gspca_dev->last_packet_type == LAST_PACKET) {
/* put the JPEG 422 header */
gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
sd->jpeg_hdr, JPEG_HDR_SZ);
}
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_setblue_balance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->blue = val;
if (gspca_dev->streaming)
setredblue(gspca_dev);
return 0;
}
static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->blue;
return 0;
}
static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->red = val;
if (gspca_dev->streaming)
setredblue(gspca_dev);
return 0;
}
static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->red;
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_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_setvflip(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->vflip = val;
if (gspca_dev->streaming)
setvflip(sd);
return 0;
}
static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->vflip;
return 0;
}
static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->infrared = val;
if (gspca_dev->streaming)
setinfrared(sd);
return 0;
}
static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->infrared;
return 0;
}
static int sd_set_jcomp(struct gspca_dev *gspca_dev,
struct v4l2_jpegcompression *jcomp)
{
struct sd *sd = (struct sd *) gspca_dev;
if (jcomp->quality < QUALITY_MIN)
sd->quality = QUALITY_MIN;
else if (jcomp->quality > QUALITY_MAX)
sd->quality = QUALITY_MAX;
else
sd->quality = jcomp->quality;
if (gspca_dev->streaming)
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
return 0;
}
static int sd_get_jcomp(struct gspca_dev *gspca_dev,
struct v4l2_jpegcompression *jcomp)
{
struct sd *sd = (struct sd *) gspca_dev;
memset(jcomp, 0, sizeof *jcomp);
jcomp->quality = sd->quality;
jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
| V4L2_JPEG_MARKER_DQT;
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,
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
#define BSI(bridge, sensor, i2c_addr) \
.driver_info = (BRIDGE_ ## bridge << 16) \
| (SENSOR_ ## sensor << 8) \
| (i2c_addr)
static const __devinitdata struct usb_device_id device_table[] = {
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)},
{USB_DEVICE(0x0458, 0x702e), BSI(SN9C120, OV7660, 0x21)},
#endif
{USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
{USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
{USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)},
{USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)},
{USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)},
{USB_DEVICE(0x06f8, 0x3004), BSI(SN9C105, OV7660, 0x21)},
{USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)},
/* bw600.inf:
{USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */
/* {USB_DEVICE(0x0c45, 0x603a), BSI(SN9C102P, OV7648, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x607a), BSI(SN9C102P, OV7648, 0x??)}, */
{USB_DEVICE(0x0c45, 0x607c), BSI(SN9C102P, HV7131R, 0x11)},
/* {USB_DEVICE(0x0c45, 0x607e), BSI(SN9C102P, OV7630, 0x??)}, */
{USB_DEVICE(0x0c45, 0x60c0), BSI(SN9C105, MI0360, 0x5d)},
/* {USB_DEVICE(0x0c45, 0x60c8), BSI(SN9C105, OM6801, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x60cc), BSI(SN9C105, HV7131GP, 0x??)}, */
{USB_DEVICE(0x0c45, 0x60ec), BSI(SN9C105, MO4000, 0x21)},
/* {USB_DEVICE(0x0c45, 0x60ef), BSI(SN9C105, ICM105C, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x60fa), BSI(SN9C105, OV7648, 0x??)}, */
{USB_DEVICE(0x0c45, 0x60fb), BSI(SN9C105, OV7660, 0x21)},
{USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)},
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)},
#endif
/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
{USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/
/*bw600.inf:*/
{USB_DEVICE(0x0c45, 0x612a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c110?*/
{USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)},
{USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x21)},
/* {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)},
#endif
{USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)},
{USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)},
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)},
#endif
{USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
/* {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */
{USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)},
{}
};
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,
#ifdef CONFIG_PM
.suspend = gspca_suspend,
.resume = gspca_resume,
#endif
};
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
int ret;
ret = usb_register(&sd_driver);
if (ret < 0)
return ret;
info("registered");
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);