|
@@ -40,8 +40,7 @@ struct sd {
|
|
|
struct gspca_dev gspca_dev; /* !! must be the first item */
|
|
|
|
|
|
/* Determined by sensor type */
|
|
|
- short maxwidth;
|
|
|
- short maxheight;
|
|
|
+ char sif;
|
|
|
|
|
|
unsigned char primary_i2c_slave; /* I2C write id of sensor */
|
|
|
|
|
@@ -85,7 +84,6 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
|
|
|
static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
|
|
|
|
|
|
static struct ctrl sd_ctrls[] = {
|
|
|
-#define SD_BRIGHTNESS 0
|
|
|
{
|
|
|
{
|
|
|
.id = V4L2_CID_BRIGHTNESS,
|
|
@@ -94,12 +92,12 @@ static struct ctrl sd_ctrls[] = {
|
|
|
.minimum = 0,
|
|
|
.maximum = 255,
|
|
|
.step = 1,
|
|
|
- .default_value = 127,
|
|
|
+#define BRIGHTNESS_DEF 127
|
|
|
+ .default_value = BRIGHTNESS_DEF,
|
|
|
},
|
|
|
.set = sd_setbrightness,
|
|
|
.get = sd_getbrightness,
|
|
|
},
|
|
|
-#define SD_CONTRAST 1
|
|
|
{
|
|
|
{
|
|
|
.id = V4L2_CID_CONTRAST,
|
|
@@ -108,21 +106,22 @@ static struct ctrl sd_ctrls[] = {
|
|
|
.minimum = 0,
|
|
|
.maximum = 255,
|
|
|
.step = 1,
|
|
|
- .default_value = 127,
|
|
|
+#define CONTRAST_DEF 127
|
|
|
+ .default_value = CONTRAST_DEF,
|
|
|
},
|
|
|
.set = sd_setcontrast,
|
|
|
.get = sd_getcontrast,
|
|
|
},
|
|
|
-#define SD_COLOR 2
|
|
|
{
|
|
|
{
|
|
|
.id = V4L2_CID_SATURATION,
|
|
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
|
- .name = "Saturation",
|
|
|
+ .name = "Color",
|
|
|
.minimum = 0,
|
|
|
.maximum = 255,
|
|
|
.step = 1,
|
|
|
- .default_value = 127,
|
|
|
+#define COLOR_DEF 127
|
|
|
+ .default_value = COLOR_DEF,
|
|
|
},
|
|
|
.set = sd_setcolors,
|
|
|
.get = sd_getcolors,
|
|
@@ -161,7 +160,7 @@ 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,
|
|
|
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
|
|
|
.colorspace = V4L2_COLORSPACE_JPEG,
|
|
|
.priv = 1},
|
|
|
{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
|
|
@@ -173,12 +172,12 @@ static struct v4l2_pix_format vga_mode[] = {
|
|
|
static struct v4l2_pix_format sif_mode[] = {
|
|
|
{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
|
|
|
.bytesperline = 176,
|
|
|
- .sizeimage = 176 * 144 * 3 / 8 + 589,
|
|
|
+ .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 + 589,
|
|
|
+ .sizeimage = 352 * 288 * 3 / 8 + 590,
|
|
|
.colorspace = V4L2_COLORSPACE_JPEG,
|
|
|
.priv = 0},
|
|
|
};
|
|
@@ -294,16 +293,6 @@ static struct v4l2_pix_format sif_mode[] = {
|
|
|
#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)
|
|
@@ -535,19 +524,6 @@ static int init_ov_sensor(struct sd *sd)
|
|
|
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.
|
|
@@ -717,21 +693,17 @@ static int ov8xx0_configure(struct sd *sd)
|
|
|
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]))
|
|
|
+ if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))
|
|
|
return -1;
|
|
|
|
|
|
/* Set sensor-specific vars */
|
|
|
- sd->maxwidth = 640;
|
|
|
- sd->maxheight = 480;
|
|
|
+/* sd->sif = 0; already done */
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -861,7 +833,7 @@ static int ov7xx0_configure(struct sd *sd)
|
|
|
{ OV7670_REG_COM7, OV7670_COM7_RESET },
|
|
|
{ OV7670_REG_TSLB, 0x04 }, /* OV */
|
|
|
{ OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
|
|
|
- { OV7670_REG_CLKRC, 0x1 },
|
|
|
+ { OV7670_REG_CLKRC, 0x01 },
|
|
|
/*
|
|
|
* Set the hardware window. These values from OV don't entirely
|
|
|
* make sense - hstop is less than hstart. But they work...
|
|
@@ -875,16 +847,12 @@ static int ov7xx0_configure(struct sd *sd)
|
|
|
{ 0x70, 0x3a }, { 0x71, 0x35 },
|
|
|
{ 0x72, 0x11 }, { 0x73, 0xf0 },
|
|
|
{ 0xa2, 0x02 },
|
|
|
-/* jfm */
|
|
|
-/* { OV7670_REG_COM10, 0x0 }, */
|
|
|
+/* { 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 },
|
|
@@ -900,13 +868,11 @@ static int ov7xx0_configure(struct sd *sd)
|
|
|
| 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 },
|
|
@@ -920,8 +886,6 @@ static int ov7xx0_configure(struct sd *sd)
|
|
|
/* 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 },
|
|
@@ -995,17 +959,10 @@ static int ov7xx0_configure(struct sd *sd)
|
|
|
{ 0x79, 0x03 }, { 0xc8, 0x40 },
|
|
|
{ 0x79, 0x05 }, { 0xc8, 0x30 },
|
|
|
{ 0x79, 0x26 },
|
|
|
-
|
|
|
-};
|
|
|
+ };
|
|
|
|
|
|
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);
|
|
|
|
|
@@ -1051,20 +1008,25 @@ static int ov7xx0_configure(struct sd *sd)
|
|
|
return low;
|
|
|
}
|
|
|
if (high == 0x76) {
|
|
|
- if (low == 0x30) {
|
|
|
+ switch (low) {
|
|
|
+ case 0x30:
|
|
|
PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");
|
|
|
sd->sensor = SEN_OV7630;
|
|
|
- } else if (low == 0x40) {
|
|
|
+ break;
|
|
|
+ case 0x40:
|
|
|
PDEBUG(D_PROBE, "Sensor is an OV7645");
|
|
|
sd->sensor = SEN_OV7640; /* FIXME */
|
|
|
- } else if (low == 0x45) {
|
|
|
+ break;
|
|
|
+ case 0x45:
|
|
|
PDEBUG(D_PROBE, "Sensor is an OV7645B");
|
|
|
sd->sensor = SEN_OV7640; /* FIXME */
|
|
|
- } else if (low == 0x48) {
|
|
|
+ break;
|
|
|
+ case 0x48:
|
|
|
PDEBUG(D_PROBE, "Sensor is an OV7648");
|
|
|
sd->sensor = SEN_OV7640; /* FIXME */
|
|
|
- } else {
|
|
|
- PDEBUG(D_PROBE, "Unknown sensor: 0x76%X", low);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low);
|
|
|
return -1;
|
|
|
}
|
|
|
} else {
|
|
@@ -1076,34 +1038,34 @@ static int ov7xx0_configure(struct sd *sd)
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
- if (sd->sensor == SEN_OV7620) {
|
|
|
+ switch (sd->sensor) {
|
|
|
+ case SEN_OV7620:
|
|
|
PDEBUG(D_PROBE, "Writing 7620 registers");
|
|
|
- if (write_i2c_regvals(sd, norm_7620,
|
|
|
- sizeof norm_7620 / sizeof norm_7620[0]))
|
|
|
+ if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
|
|
|
return -1;
|
|
|
- } else if (sd->sensor == SEN_OV7630) {
|
|
|
+ break;
|
|
|
+ case SEN_OV7630:
|
|
|
PDEBUG(D_ERR, "7630 is not supported by this driver version");
|
|
|
return -1;
|
|
|
- } else if (sd->sensor == SEN_OV7640) {
|
|
|
+ case SEN_OV7640:
|
|
|
PDEBUG(D_PROBE, "Writing 7640 registers");
|
|
|
- if (write_i2c_regvals(sd, norm_7640,
|
|
|
- sizeof norm_7640 / sizeof norm_7640[0]))
|
|
|
+ if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
|
|
|
return -1;
|
|
|
- } else if (sd->sensor == SEN_OV7670) {
|
|
|
+ break;
|
|
|
+ case SEN_OV7670:
|
|
|
PDEBUG(D_PROBE, "Writing 7670 registers");
|
|
|
- if (write_i2c_regvals(sd, norm_7670,
|
|
|
- sizeof norm_7670 / sizeof norm_7670[0]))
|
|
|
+ if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
|
|
|
return -1;
|
|
|
- } else {
|
|
|
+ break;
|
|
|
+ default:
|
|
|
PDEBUG(D_PROBE, "Writing 7610 registers");
|
|
|
- if (write_i2c_regvals(sd, norm_7610,
|
|
|
- sizeof norm_7610 / sizeof norm_7610[0]))
|
|
|
+ if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
|
|
|
return -1;
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
/* Set sensor-specific vars */
|
|
|
- sd->maxwidth = 640;
|
|
|
- sd->maxheight = 480;
|
|
|
+/* sd->sif = 0; already done */
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1257,43 +1219,45 @@ static int ov6xx0_configure(struct sd *sd)
|
|
|
/* 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) {
|
|
|
+ switch (rc) {
|
|
|
+ case 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) {
|
|
|
+ break;
|
|
|
+ case 0x01:
|
|
|
sd->sensor = SEN_OV6620;
|
|
|
- PDEBUG(D_PROBE, "Sensor is an OV6620");
|
|
|
- } else if (rc == 0x02) {
|
|
|
+ break;
|
|
|
+ case 0x02:
|
|
|
sd->sensor = SEN_OV6630;
|
|
|
PDEBUG(D_PROBE, "Sensor is an OV66308AE");
|
|
|
- } else if (rc == 0x03) {
|
|
|
+ break;
|
|
|
+ case 0x03:
|
|
|
sd->sensor = SEN_OV6630;
|
|
|
PDEBUG(D_PROBE, "Sensor is an OV66308AF");
|
|
|
- } else if (rc == 0x90) {
|
|
|
+ break;
|
|
|
+ case 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 {
|
|
|
+ break;
|
|
|
+ default:
|
|
|
PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc);
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
/* Set sensor-specific vars */
|
|
|
- sd->maxwidth = 352;
|
|
|
- sd->maxheight = 288;
|
|
|
+ sd->sif = 1;
|
|
|
|
|
|
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]))
|
|
|
+ if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
|
|
|
return -1;
|
|
|
} else {
|
|
|
PDEBUG(D_PROBE, "Writing 6x30 registers");
|
|
|
- if (write_i2c_regvals(sd, norm_6x30,
|
|
|
- sizeof norm_6x30 / sizeof norm_6x30[0]))
|
|
|
+ if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
|
|
|
return -1;
|
|
|
}
|
|
|
return 0;
|
|
@@ -1302,14 +1266,8 @@ static int ov6xx0_configure(struct sd *sd)
|
|
|
/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
|
|
|
static void ov51x_led_control(struct sd *sd, int on)
|
|
|
{
|
|
|
- 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); */
|
|
|
+/* PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off"); */
|
|
|
+ reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */
|
|
|
}
|
|
|
|
|
|
/* this function is called at probe time */
|
|
@@ -1319,11 +1277,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
|
|
|
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 },
|
|
@@ -1340,9 +1295,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
|
|
|
|
|
|
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 */
|
|
@@ -1391,16 +1343,16 @@ static int sd_config(struct gspca_dev *gspca_dev,
|
|
|
|
|
|
cam = &gspca_dev->cam;
|
|
|
cam->epaddr = OV511_ENDPOINT_ADDRESS;
|
|
|
- if (sd->maxwidth == 640) {
|
|
|
+ if (!sd->sif) {
|
|
|
cam->cam_mode = vga_mode;
|
|
|
- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
|
|
|
+ cam->nmodes = ARRAY_SIZE(vga_mode);
|
|
|
} else {
|
|
|
cam->cam_mode = sif_mode;
|
|
|
- cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
|
|
|
+ cam->nmodes = ARRAY_SIZE(sif_mode);
|
|
|
}
|
|
|
- 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->brightness = BRIGHTNESS_DEF;
|
|
|
+ sd->contrast = CONTRAST_DEF;
|
|
|
+ sd->colors = COLOR_DEF;
|
|
|
sd->hflip = HFLIP_DEF;
|
|
|
sd->vflip = VFLIP_DEF;
|
|
|
return 0;
|
|
@@ -1422,8 +1374,7 @@ static int sd_open(struct gspca_dev *gspca_dev)
|
|
|
*
|
|
|
* 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 int ov519_mode_init_regs(struct sd *sd)
|
|
|
{
|
|
|
static const struct ov_regvals mode_init_519_ov7670[] = {
|
|
|
{ 0x5d, 0x03 }, /* Turn off suspend mode */
|
|
@@ -1469,36 +1420,23 @@ static int ov519_mode_init_regs(struct sd *sd,
|
|
|
/* 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;
|
|
|
+ if (sd->sensor == SEN_OV7640) {
|
|
|
+ /* Select 8-bit input mode */
|
|
|
+ reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10);
|
|
|
+ }
|
|
|
} 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_H_SIZE, sd->gspca_dev.width >> 4);
|
|
|
+ reg_w(sd, OV519_CAM_V_SIZE, sd->gspca_dev.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);
|
|
@@ -1513,9 +1451,10 @@ static int ov519_mode_init_regs(struct sd *sd,
|
|
|
|
|
|
/* FIXME: These are only valid at the max resolution. */
|
|
|
sd->clockdiv = 0;
|
|
|
- if (sd->sensor == SEN_OV7640) {
|
|
|
+ switch (sd->sensor) {
|
|
|
+ case SEN_OV7640:
|
|
|
switch (sd->frame_rate) {
|
|
|
-/*jfm: default was 30 fps */
|
|
|
+/*fixme: default was 30 fps */
|
|
|
case 30:
|
|
|
reg_w(sd, 0xa4, 0x0c);
|
|
|
reg_w(sd, 0x23, 0xff);
|
|
@@ -1545,7 +1484,8 @@ static int ov519_mode_init_regs(struct sd *sd,
|
|
|
sd->clockdiv = 1;
|
|
|
break;
|
|
|
}
|
|
|
- } else if (sd->sensor == SEN_OV8610) {
|
|
|
+ break;
|
|
|
+ case SEN_OV8610:
|
|
|
switch (sd->frame_rate) {
|
|
|
default: /* 15 fps */
|
|
|
/* case 15: */
|
|
@@ -1561,41 +1501,37 @@ static int ov519_mode_init_regs(struct sd *sd,
|
|
|
reg_w(sd, 0x23, 0x1b);
|
|
|
break;
|
|
|
}
|
|
|
- sd->clockdiv = 0;
|
|
|
- } else if (sd->sensor == SEN_OV7670) { /* guesses, based on 7640 */
|
|
|
+ break;
|
|
|
+ case SEN_OV7670: /* guesses, based on 7640 */
|
|
|
PDEBUG(D_STREAM, "Setting framerate to %d fps",
|
|
|
(sd->frame_rate == 0) ? 15 : sd->frame_rate);
|
|
|
+ reg_w(sd, 0xa4, 0x10);
|
|
|
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);
|
|
|
+ default:
|
|
|
+/* case 15: */
|
|
|
reg_w(sd, 0x23, 0xff);
|
|
|
sd->clockdiv = 1;
|
|
|
break;
|
|
|
}
|
|
|
+ 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)
|
|
|
+static int mode_init_ov_sensor_regs(struct sd *sd)
|
|
|
{
|
|
|
- int qvga = win->quarter;
|
|
|
+ struct gspca_dev *gspca_dev;
|
|
|
+ int qvga;
|
|
|
+
|
|
|
+ gspca_dev = &sd->gspca_dev;
|
|
|
+ qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
|
|
|
|
|
|
/******** Mode (VGA/QVGA) and sensor specific regs ********/
|
|
|
switch (sd->sensor) {
|
|
@@ -1639,8 +1575,6 @@ static int mode_init_ov_sensor_regs(struct sd *sd,
|
|
|
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;
|
|
@@ -1649,24 +1583,21 @@ static int mode_init_ov_sensor_regs(struct sd *sd,
|
|
|
}
|
|
|
|
|
|
/******** 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);
|
|
|
- }
|
|
|
+ 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 */
|
|
|
+ /* 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 */
|
|
|
+ /* OV7640 is 8-bit only */
|
|
|
|
|
|
- if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640)
|
|
|
- i2c_w_mask(sd, 0x13, 0x00, 0x20);
|
|
|
-/* } */
|
|
|
+ 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
|
|
@@ -1675,14 +1606,14 @@ static int mode_init_ov_sensor_regs(struct sd *sd,
|
|
|
|
|
|
/* Clock down */
|
|
|
i2c_w(sd, 0x2a, 0x04);
|
|
|
- i2c_w(sd, 0x11, win->clockdiv);
|
|
|
+ i2c_w(sd, 0x11, sd->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);
|
|
|
+ } else if (sd->clockdiv >= 0) {
|
|
|
+ i2c_w(sd, 0x11, sd->clockdiv);
|
|
|
}
|
|
|
|
|
|
/******** Special Features ********/
|
|
@@ -1702,7 +1633,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd,
|
|
|
/* 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*/)
|
|
|
+ if (!qvga)
|
|
|
i2c_w(sd, 0x35, 0x9e);
|
|
|
else
|
|
|
i2c_w(sd, 0x35, 0x1e);
|
|
@@ -1710,33 +1641,31 @@ static int mode_init_ov_sensor_regs(struct sd *sd,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void sethflip(struct sd *sd)
|
|
|
-{
|
|
|
- if (sd->gspca_dev.streaming)
|
|
|
- ov51x_stop(sd);
|
|
|
- i2c_w_mask(sd, OV7670_REG_MVFP,
|
|
|
- OV7670_MVFP_MIRROR * sd->hflip, OV7670_MVFP_MIRROR);
|
|
|
- if (sd->gspca_dev.streaming)
|
|
|
- ov51x_restart(sd);
|
|
|
-}
|
|
|
-
|
|
|
-static void setvflip(struct sd *sd)
|
|
|
+static void sethvflip(struct sd *sd)
|
|
|
{
|
|
|
+ if (sd->sensor != SEN_OV7670)
|
|
|
+ return;
|
|
|
if (sd->gspca_dev.streaming)
|
|
|
ov51x_stop(sd);
|
|
|
i2c_w_mask(sd, OV7670_REG_MVFP,
|
|
|
- OV7670_MVFP_VFLIP * sd->vflip, OV7670_MVFP_VFLIP);
|
|
|
+ OV7670_MVFP_MIRROR * sd->hflip
|
|
|
+ | OV7670_MVFP_VFLIP * sd->vflip,
|
|
|
+ OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP);
|
|
|
if (sd->gspca_dev.streaming)
|
|
|
ov51x_restart(sd);
|
|
|
}
|
|
|
|
|
|
-static int set_ov_sensor_window(struct sd *sd,
|
|
|
- struct ovsensor_window *win)
|
|
|
+static int set_ov_sensor_window(struct sd *sd)
|
|
|
{
|
|
|
+ struct gspca_dev *gspca_dev;
|
|
|
+ int qvga;
|
|
|
int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
|
|
|
int ret, hstart, hstop, vstop, vstart;
|
|
|
__u8 v;
|
|
|
|
|
|
+ gspca_dev = &sd->gspca_dev;
|
|
|
+ qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
|
|
|
+
|
|
|
/* 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) {
|
|
@@ -1781,7 +1710,7 @@ static int set_ov_sensor_window(struct sd *sd,
|
|
|
switch (sd->sensor) {
|
|
|
case SEN_OV6620:
|
|
|
case SEN_OV6630:
|
|
|
- if (win->quarter) { /* QCIF */
|
|
|
+ if (qvga) { /* QCIF */
|
|
|
hwscale = 0;
|
|
|
vwscale = 0;
|
|
|
} else { /* CIF */
|
|
@@ -1791,7 +1720,7 @@ static int set_ov_sensor_window(struct sd *sd,
|
|
|
}
|
|
|
break;
|
|
|
case SEN_OV8610:
|
|
|
- if (win->quarter) { /* QSVGA */
|
|
|
+ if (qvga) { /* QSVGA */
|
|
|
hwscale = 1;
|
|
|
vwscale = 1;
|
|
|
} else { /* SVGA */
|
|
@@ -1800,7 +1729,7 @@ static int set_ov_sensor_window(struct sd *sd,
|
|
|
}
|
|
|
break;
|
|
|
default: /* SEN_OV7xx0 */
|
|
|
- if (win->quarter) { /* QVGA */
|
|
|
+ if (qvga) { /* QVGA */
|
|
|
hwscale = 1;
|
|
|
vwscale = 0;
|
|
|
} else { /* VGA */
|
|
@@ -1809,7 +1738,7 @@ static int set_ov_sensor_window(struct sd *sd,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- ret = mode_init_ov_sensor_regs(sd, win);
|
|
|
+ ret = mode_init_ov_sensor_regs(sd);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
|
|
@@ -1830,7 +1759,7 @@ static int set_ov_sensor_window(struct sd *sd,
|
|
|
/* 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
|
|
|
+ if (qvga) { /* QVGA from ov7670.c by
|
|
|
* Jonathan Corbet */
|
|
|
hstart = 164;
|
|
|
hstop = 20;
|
|
@@ -1844,76 +1773,45 @@ static int set_ov_sensor_window(struct sd *sd,
|
|
|
}
|
|
|
/* 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);
|
|
|
+ i2c_w(sd, OV7670_REG_HSTART, hstart >> 3);
|
|
|
+ i2c_w(sd, OV7670_REG_HSTOP, hstop >> 3);
|
|
|
v = i2c_r(sd, OV7670_REG_HREF);
|
|
|
v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x07);
|
|
|
msleep(10); /* need to sleep between read and write to
|
|
|
* same reg! */
|
|
|
i2c_w(sd, OV7670_REG_HREF, v);
|
|
|
|
|
|
- i2c_w(sd, OV7670_REG_VSTART, (vstart >> 2) & 0xff);
|
|
|
- i2c_w(sd, OV7670_REG_VSTOP, (vstop >> 2) & 0xff);
|
|
|
+ i2c_w(sd, OV7670_REG_VSTART, vstart >> 2);
|
|
|
+ i2c_w(sd, OV7670_REG_VSTOP, vstop >> 2);
|
|
|
v = i2c_r(sd, OV7670_REG_VREF);
|
|
|
v = (v & 0xc0) | ((vstop & 0x3) << 2) | (vstart & 0x03);
|
|
|
msleep(10); /* need to sleep between read and write to
|
|
|
* same reg! */
|
|
|
i2c_w(sd, OV7670_REG_VREF, v);
|
|
|
- sethflip(sd);
|
|
|
- setvflip(sd);
|
|
|
+ sethvflip(sd);
|
|
|
} 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));
|
|
|
+ i2c_w(sd, 0x17, hwsbase);
|
|
|
+ i2c_w(sd, 0x18, hwebase + (sd->gspca_dev.width >> hwscale));
|
|
|
+ i2c_w(sd, 0x19, vwsbase);
|
|
|
+ i2c_w(sd, 0x1a, vwebase + (sd->gspca_dev.height >> vwscale));
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-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);
|
|
|
+ ret = ov519_mode_init_regs(sd);
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
|
- ret = ov_sensor_mode_setup(sd, gspca_dev->width, gspca_dev->height);
|
|
|
+ ret = set_ov_sensor_window(sd);
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
|
|
|
|
- ret = ov51x_restart((struct sd *) gspca_dev);
|
|
|
+ ret = ov51x_restart(sd);
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
|
PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
|
|
@@ -1987,12 +1885,10 @@ 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)
|
|
|
+/* if (gspca_dev->streaming)
|
|
|
* ov51x_stop(sd); */
|
|
|
switch (sd->sensor) {
|
|
|
case SEN_OV8610:
|
|
@@ -2010,12 +1906,12 @@ static void setbrightness(struct gspca_dev *gspca_dev)
|
|
|
i2c_w(sd, OV7610_REG_BRT, val);
|
|
|
break;
|
|
|
case SEN_OV7670:
|
|
|
-/*jfm - from windblows
|
|
|
+/*win trace
|
|
|
* 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)
|
|
|
+/* if (gspca_dev->streaming)
|
|
|
* ov51x_restart(sd); */
|
|
|
}
|
|
|
|
|
@@ -2023,12 +1919,10 @@ 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)
|
|
|
+/* if (gspca_dev->streaming)
|
|
|
ov51x_stop(sd); */
|
|
|
switch (sd->sensor) {
|
|
|
case SEN_OV7610:
|
|
@@ -2065,7 +1959,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
|
|
|
i2c_w(sd, OV7670_REG_CONTRAS, val >> 1);
|
|
|
break;
|
|
|
}
|
|
|
-/* if (was_streaming)
|
|
|
+/* if (gspca_dev->streaming)
|
|
|
ov51x_restart(sd); */
|
|
|
}
|
|
|
|
|
@@ -2073,12 +1967,10 @@ 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)
|
|
|
+/* if (gspca_dev->streaming)
|
|
|
ov51x_stop(sd); */
|
|
|
switch (sd->sensor) {
|
|
|
case SEN_OV8610:
|
|
@@ -2104,7 +1996,7 @@ static void setcolors(struct gspca_dev *gspca_dev)
|
|
|
/* set REG_COM13 values for UV sat auto mode */
|
|
|
break;
|
|
|
}
|
|
|
-/* if (was_streaming)
|
|
|
+/* if (gspca_dev->streaming)
|
|
|
ov51x_restart(sd); */
|
|
|
}
|
|
|
|
|
@@ -2164,7 +2056,7 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
|
|
|
struct sd *sd = (struct sd *) gspca_dev;
|
|
|
|
|
|
sd->hflip = val;
|
|
|
- sethflip(sd);
|
|
|
+ sethvflip(sd);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -2181,7 +2073,7 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
|
|
|
struct sd *sd = (struct sd *) gspca_dev;
|
|
|
|
|
|
sd->vflip = val;
|
|
|
- setvflip(sd);
|
|
|
+ sethvflip(sd);
|
|
|
return 0;
|
|
|
}
|
|
|
|