#include "gspca.h"
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
-static const char version[] = "2.1.7";
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 8)
+static const char version[] = "2.1.8";
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
unsigned char autogain;
unsigned char autogain_ignore_frames;
unsigned char freq; /* light freq filter setting */
+ unsigned char saturation;
+ unsigned char hue;
+ unsigned char contrast;
unsigned char fr_h_sz; /* size of frame header */
char sensor; /* Type of image sensor chip */
static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
{
.set = sd_setfreq,
.get = sd_getfreq,
},
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define SATURATION_DEF 127
+ .default_value = SATURATION_DEF,
+ },
+ .set = sd_setsaturation,
+ .get = sd_getsaturation,
+ },
+ {
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define HUE_DEF 127
+ .default_value = HUE_DEF,
+ },
+ .set = sd_sethue,
+ .get = sd_gethue,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define CONTRAST_DEF 127
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
};
static struct v4l2_pix_format vga_mode[] = {
{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
{0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
- /* Disable autobright ? */
- {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10},
+ /* Enable rgb brightness control */
+ {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
+ /* HDG: Note windows uses the line below, which sets both register 0x60
+ and 0x61 I believe these registers of the ov6650 are identical as
+ those of the ov7630, because if this is true the windows settings
+ add a bit additional red gain and a lot additional blue gain, which
+ matches my findings that the windows settings make blue much too
+ blue and red a little too red.
+ {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
/* Some more unknown stuff */
{0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
{0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
tline * 4 * reg10, which explains why the reg10max we've
found experimentally for the ov6650 is exactly half that of
the ov6645. The ov7630 datasheet says the max is 0x41. */
- const int reg10_max = (sd->sensor == SENSOR_OV6650)? 0x4d:0x41;
+ const int reg10_max = (sd->sensor == SENSOR_OV6650)
+ ? 0x4d : 0x41;
reg11 = (60 * sd->exposure + 999) / 1000;
if (reg11 < 1)
i2c[3] = 0;
break;
case 1: /* 50 hz */
- i2c[3] = (sd->sensor == SENSOR_OV6650)? 0x4f:0x8a;
+ i2c[3] = (sd->sensor == SENSOR_OV6650)
+ ? 0x4f : 0x8a;
break;
}
i2c[1] = sd->sensor_addr;
}
}
+static void setsaturation(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->sensor) {
+/* case SENSOR_OV6650: */
+ case SENSOR_OV7630_3:
+ case SENSOR_OV7630: {
+ __u8 i2c[] = {0xa0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10};
+ i2c[1] = sd->sensor_addr;
+ i2c[3] = sd->saturation & 0xf0;
+ if (i2c_w(gspca_dev, i2c) < 0)
+ PDEBUG(D_ERR, "i2c error setsaturation");
+ else
+ PDEBUG(D_CONF, "saturation set to: %d",
+ (int)sd->saturation);
+ break;
+ }
+ }
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->sensor) {
+/* case SENSOR_OV6650: */
+ case SENSOR_OV7630_3:
+ case SENSOR_OV7630: {
+ __u8 i2c[] = {0xa0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10};
+ i2c[1] = sd->sensor_addr;
+ i2c[3] = 0x20 | (sd->hue >> 3);
+ if (i2c_w(gspca_dev, i2c) < 0)
+ PDEBUG(D_ERR, "i2c error setsaturation");
+ else
+ PDEBUG(D_CONF, "hue set to: %d", (int)sd->hue);
+ break;
+ }
+ }
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->sensor) {
+/* case SENSOR_OV6650: */
+ case SENSOR_OV7630_3:
+ case SENSOR_OV7630: {
+ __u8 i2c[] = {0xa0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10};
+ i2c[1] = sd->sensor_addr;
+ i2c[3] = 0x20 | (sd->contrast >> 3);
+ if (i2c_w(gspca_dev, i2c) < 0)
+ PDEBUG(D_ERR, "i2c error setcontrast");
+ else
+ PDEBUG(D_CONF, "contrast set to: %d",
+ (int)sd->contrast);
+ break;
+ }
+ }
+}
+
static void do_autogain(struct gspca_dev *gspca_dev)
{
sd->fr_h_sz = 12; /* default size of the frame header */
sd->sd_desc.nctrls = 2; /* default nb of ctrls */
sd->autogain = AUTOGAIN_DEF; /* default is autogain active */
- sd->freq = FREQ_DEF;
product = id->idProduct;
/* switch (id->idVendor) { */
sd->sensor = SENSOR_OV6650;
sd->sensor_has_gain = 1;
sd->sensor_addr = 0x60;
- sd->sd_desc.nctrls = 4;
+ sd->sd_desc.nctrls = 5;
sd->sd_desc.dq_callback = do_autogain;
sif = 1;
break;
sd->sensor_addr = 0x21;
sd->fr_h_sz = 18; /* size of frame header */
sd->sensor_has_gain = 1;
- sd->sd_desc.nctrls = 5;
+ sd->sd_desc.nctrls = 8;
sd->sd_desc.dq_callback = do_autogain;
sd->autogain = 0;
break;
sd->brightness = BRIGHTNESS_DEF;
sd->gain = GAIN_DEF;
sd->exposure = EXPOSURE_DEF;
+ sd->freq = FREQ_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->saturation = SATURATION_DEF;
+ sd->hue = HUE_DEF;
if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
return 0;
case SENSOR_OV7630:
reg01 = 0x06;
reg17 = 0x29;
- l = 0x10;
+ l = sizeof initOv7630;
break;
case SENSOR_OV7630_3:
reg01 = 0x44;
setbrightness(gspca_dev);
setexposure(gspca_dev);
setfreq(gspca_dev);
+ setsaturation(gspca_dev);
+ sethue(gspca_dev);
+ setcontrast(gspca_dev);
sd->autogain_ignore_frames = 0;
atomic_set(&sd->avg_lum, -1);
return 0;
}
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->saturation = val;
+ if (gspca_dev->streaming)
+ setsaturation(gspca_dev);
+ return 0;
+}
+
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->saturation;
+ return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hue = val;
+ if (gspca_dev->streaming)
+ sethue(gspca_dev);
+ return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->hue;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
{USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
{USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
{USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
+#endif
{USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
+#ifndef CONFIG_USB_SN9C102
{USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
{USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
{USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},