aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca/sn9c20x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/gspca/sn9c20x.c')
-rw-r--r--drivers/media/video/gspca/sn9c20x.c1138
1 files changed, 503 insertions, 635 deletions
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 9e198b45c3c8..7e71aa2d2522 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -1,5 +1,7 @@
/*
* Sonix sn9c201 sn9c202 library
+ *
+ * Copyright (C) 2012 Jean-Francois Moine <http://moinejf.free.fr>
* Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com>
* Copyright (C) 2009 Brian Johnson <brijohn@gmail.com>
*
@@ -33,8 +35,6 @@ MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
MODULE_LICENSE("GPL");
-#define MODULE_NAME "sn9c20x"
-
/*
* Pixel format private data
*/
@@ -66,10 +66,37 @@ MODULE_LICENSE("GPL");
#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */
#define FLIP_DETECT 0x4
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ SATURATION,
+ HUE,
+ GAMMA,
+ BLUE,
+ RED,
+ VFLIP,
+ HFLIP,
+ EXPOSURE,
+ GAIN,
+ AUTOGAIN,
+ QUALITY,
+ NCTRLS /* number of controls */
+};
+
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev;
+ struct gspca_ctrl ctrls[NCTRLS];
+
+ struct work_struct work;
+ struct workqueue_struct *work_thread;
+
+ u32 pktsz; /* (used by pkt_scan) */
+ u16 npkt;
+ s8 nchg;
+ u8 fmt; /* (used for JPEG QTAB update */
+
#define MIN_AVG_LUM 80
#define MAX_AVG_LUM 130
atomic_t avg_lum;
@@ -77,31 +104,18 @@ struct sd {
u8 older_step;
u8 exposure_step;
- u8 brightness;
- u8 contrast;
- u8 saturation;
- s16 hue;
- u8 gamma;
- u8 red;
- u8 blue;
-
- u8 hflip;
- u8 vflip;
- u8 gain;
- u16 exposure;
- u8 auto_exposure;
-
u8 i2c_addr;
u8 sensor;
u8 hstart;
u8 vstart;
u8 jpeg_hdr[JPEG_HDR_SZ];
- u8 quality;
u8 flags;
};
+static void qual_upd(struct work_struct *work);
+
struct i2c_reg_u8 {
u8 reg;
u8 val;
@@ -112,31 +126,6 @@ struct i2c_reg_u16 {
u16 val;
};
-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_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_setgamma(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getbluebalance(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_sethflip(struct gspca_dev *gspca_dev, s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
-
static const struct dmi_system_id flip_dmi_table[] = {
{
.ident = "MSI MS-1034",
@@ -177,9 +166,16 @@ static const struct dmi_system_id flip_dmi_table[] = {
{}
};
-static const struct ctrl sd_ctrls[] = {
- {
-#define BRIGHTNESS_IDX 0
+static void set_cmatrix(struct gspca_dev *gspca_dev);
+static void set_gamma(struct gspca_dev *gspca_dev);
+static void set_redblue(struct gspca_dev *gspca_dev);
+static void set_hvflip(struct gspca_dev *gspca_dev);
+static void set_exposure(struct gspca_dev *gspca_dev);
+static void set_gain(struct gspca_dev *gspca_dev);
+static void set_quality(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -187,14 +183,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
-#define BRIGHTNESS_DEFAULT 0x7f
- .default_value = BRIGHTNESS_DEFAULT,
+ .default_value = 0x7f
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set_control = set_cmatrix
},
- {
-#define CONTRAST_IDX 1
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -202,14 +195,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
-#define CONTRAST_DEFAULT 0x7f
- .default_value = CONTRAST_DEFAULT,
+ .default_value = 0x7f
},
- .set = sd_setcontrast,
- .get = sd_getcontrast,
+ .set_control = set_cmatrix
},
- {
-#define SATURATION_IDX 2
+[SATURATION] = {
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -217,14 +207,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
-#define SATURATION_DEFAULT 0x7f
- .default_value = SATURATION_DEFAULT,
+ .default_value = 0x7f
},
- .set = sd_setsaturation,
- .get = sd_getsaturation,
+ .set_control = set_cmatrix
},
- {
-#define HUE_IDX 3
+[HUE] = {
{
.id = V4L2_CID_HUE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -232,14 +219,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = -180,
.maximum = 180,
.step = 1,
-#define HUE_DEFAULT 0
- .default_value = HUE_DEFAULT,
+ .default_value = 0
},
- .set = sd_sethue,
- .get = sd_gethue,
+ .set_control = set_cmatrix
},
- {
-#define GAMMA_IDX 4
+[GAMMA] = {
{
.id = V4L2_CID_GAMMA,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -247,14 +231,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
-#define GAMMA_DEFAULT 0x10
- .default_value = GAMMA_DEFAULT,
+ .default_value = 0x10
},
- .set = sd_setgamma,
- .get = sd_getgamma,
+ .set_control = set_gamma
},
- {
-#define BLUE_IDX 5
+[BLUE] = {
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -262,14 +243,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0x7f,
.step = 1,
-#define BLUE_DEFAULT 0x28
- .default_value = BLUE_DEFAULT,
+ .default_value = 0x28
},
- .set = sd_setbluebalance,
- .get = sd_getbluebalance,
+ .set_control = set_redblue
},
- {
-#define RED_IDX 6
+[RED] = {
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -277,14 +255,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0x7f,
.step = 1,
-#define RED_DEFAULT 0x28
- .default_value = RED_DEFAULT,
+ .default_value = 0x28
},
- .set = sd_setredbalance,
- .get = sd_getredbalance,
+ .set_control = set_redblue
},
- {
-#define HFLIP_IDX 7
+[HFLIP] = {
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -292,14 +267,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define HFLIP_DEFAULT 0
- .default_value = HFLIP_DEFAULT,
+ .default_value = 0,
},
- .set = sd_sethflip,
- .get = sd_gethflip,
+ .set_control = set_hvflip
},
- {
-#define VFLIP_IDX 8
+[VFLIP] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -307,14 +279,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define VFLIP_DEFAULT 0
- .default_value = VFLIP_DEFAULT,
+ .default_value = 0,
},
- .set = sd_setvflip,
- .get = sd_getvflip,
+ .set_control = set_hvflip
},
- {
-#define EXPOSURE_IDX 9
+[EXPOSURE] = {
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -322,14 +291,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0x1780,
.step = 1,
-#define EXPOSURE_DEFAULT 0x33
- .default_value = EXPOSURE_DEFAULT,
+ .default_value = 0x33,
},
- .set = sd_setexposure,
- .get = sd_getexposure,
+ .set_control = set_exposure
},
- {
-#define GAIN_IDX 10
+[GAIN] = {
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -337,14 +303,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 28,
.step = 1,
-#define GAIN_DEFAULT 0x00
- .default_value = GAIN_DEFAULT,
+ .default_value = 0,
},
- .set = sd_setgain,
- .get = sd_getgain,
+ .set_control = set_gain
},
- {
-#define AUTOGAIN_IDX 11
+[AUTOGAIN] = {
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -352,11 +315,23 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define AUTO_EXPOSURE_DEFAULT 1
- .default_value = AUTO_EXPOSURE_DEFAULT,
+ .default_value = 1,
+ },
+ },
+[QUALITY] = {
+ {
+ .id = V4L2_CID_JPEG_COMPRESSION_QUALITY,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Compression Quality",
+#define QUALITY_MIN 50
+#define QUALITY_MAX 90
+#define QUALITY_DEF 80
+ .minimum = QUALITY_MIN,
+ .maximum = QUALITY_MAX,
+ .step = 1,
+ .default_value = QUALITY_DEF,
},
- .set = sd_setautoexposure,
- .get = sd_getautoexposure,
+ .set_control = set_quality
},
};
@@ -876,7 +851,7 @@ static u8 hv7131r_gain[] = {
};
static struct i2c_reg_u8 soi968_init[] = {
- {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
+ {0x0c, 0x00}, {0x0f, 0x1f},
{0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
{0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
{0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
@@ -902,7 +877,7 @@ static struct i2c_reg_u8 ov7660_init[] = {
};
static struct i2c_reg_u8 ov7670_init[] = {
- {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
+ {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
{0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
{0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
{0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
@@ -959,7 +934,7 @@ static struct i2c_reg_u8 ov7670_init[] = {
};
static struct i2c_reg_u8 ov9650_init[] = {
- {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
+ {0x00, 0x00}, {0x01, 0x78},
{0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
{0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
{0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
@@ -989,7 +964,7 @@ static struct i2c_reg_u8 ov9650_init[] = {
};
static struct i2c_reg_u8 ov9655_init[] = {
- {0x12, 0x80}, {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
+ {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
{0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
{0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
{0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
@@ -1112,10 +1087,13 @@ static struct i2c_reg_u8 hv7131r_init[] = {
{0x23, 0x09}, {0x01, 0x08},
};
-static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
+static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
{
struct usb_device *dev = gspca_dev->dev;
int result;
+
+ if (gspca_dev->usb_err < 0)
+ return;
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
0x00,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1125,17 +1103,19 @@ static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
length,
500);
if (unlikely(result < 0 || result != length)) {
- pr_err("Read register failed 0x%02X\n", reg);
- return -EIO;
+ pr_err("Read register %02x failed %d\n", reg, result);
+ gspca_dev->usb_err = result;
}
- return 0;
}
-static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
+static void reg_w(struct gspca_dev *gspca_dev, u16 reg,
const u8 *buffer, int length)
{
struct usb_device *dev = gspca_dev->dev;
int result;
+
+ if (gspca_dev->usb_err < 0)
+ return;
memcpy(gspca_dev->usb_buf, buffer, length);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
0x08,
@@ -1146,38 +1126,41 @@ static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
length,
500);
if (unlikely(result < 0 || result != length)) {
- pr_err("Write register failed index 0x%02X\n", reg);
- return -EIO;
+ pr_err("Write register %02x failed %d\n", reg, result);
+ gspca_dev->usb_err = result;
}
- return 0;
}
-static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
+static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
{
- u8 data[1] = {value};
- return reg_w(gspca_dev, reg, data, 1);
+ reg_w(gspca_dev, reg, &value, 1);
}
-static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
+static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
{
int i;
+
reg_w(gspca_dev, 0x10c0, buffer, 8);
for (i = 0; i < 5; i++) {
reg_r(gspca_dev, 0x10c0, 1);
+ if (gspca_dev->usb_err < 0)
+ return;
if (gspca_dev->usb_buf[0] & 0x04) {
- if (gspca_dev->usb_buf[0] & 0x08)
- return -EIO;
- return 0;
+ if (gspca_dev->usb_buf[0] & 0x08) {
+ pr_err("i2c_w error\n");
+ gspca_dev->usb_err = -EIO;
+ }
+ return;
}
- msleep(1);
+ msleep(10);
}
- return -EIO;
+ pr_err("i2c_w reg %02x no response\n", buffer[2]);
+/* gspca_dev->usb_err = -EIO; fixme: may occur */
}
-static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
{
struct sd *sd = (struct sd *) gspca_dev;
-
u8 row[8];
/*
@@ -1193,10 +1176,19 @@ static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
row[6] = 0x00;
row[7] = 0x10;
- return i2c_w(gspca_dev, row);
+ i2c_w(gspca_dev, row);
+}
+
+static void i2c_w1_buf(struct gspca_dev *gspca_dev,
+ struct i2c_reg_u8 *buf, int sz)
+{
+ while (--sz >= 0) {
+ i2c_w1(gspca_dev, buf->reg, buf->val);
+ buf++;
+ }
}
-static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
+static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
@@ -1208,16 +1200,25 @@ static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
row[0] = 0x81 | (3 << 4);
row[1] = sd->i2c_addr;
row[2] = reg;
- row[3] = (val >> 8) & 0xff;
- row[4] = val & 0xff;
+ row[3] = val >> 8;
+ row[4] = val;
row[5] = 0x00;
row[6] = 0x00;
row[7] = 0x10;
- return i2c_w(gspca_dev, row);
+ i2c_w(gspca_dev, row);
+}
+
+static void i2c_w2_buf(struct gspca_dev *gspca_dev,
+ struct i2c_reg_u16 *buf, int sz)
+{
+ while (--sz >= 0) {
+ i2c_w2(gspca_dev, buf->reg, buf->val);
+ buf++;
+ }
}
-static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
+static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
@@ -1230,19 +1231,15 @@ static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
row[5] = 0;
row[6] = 0;
row[7] = 0x10;
- if (i2c_w(gspca_dev, row) < 0)
- return -EIO;
+ i2c_w(gspca_dev, row);
row[0] = 0x81 | (1 << 4) | 0x02;
row[2] = 0;
- if (i2c_w(gspca_dev, row) < 0)
- return -EIO;
- if (reg_r(gspca_dev, 0x10c2, 5) < 0)
- return -EIO;
+ i2c_w(gspca_dev, row);
+ reg_r(gspca_dev, 0x10c2, 5);
*val = gspca_dev->usb_buf[4];
- return 0;
}
-static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
+static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
@@ -1255,233 +1252,204 @@ static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
row[5] = 0;
row[6] = 0;
row[7] = 0x10;
- if (i2c_w(gspca_dev, row) < 0)
- return -EIO;
+ i2c_w(gspca_dev, row);
row[0] = 0x81 | (2 << 4) | 0x02;
row[2] = 0;
- if (i2c_w(gspca_dev, row) < 0)
- return -EIO;
- if (reg_r(gspca_dev, 0x10c2, 5) < 0)
- return -EIO;
+ i2c_w(gspca_dev, row);
+ reg_r(gspca_dev, 0x10c2, 5);
*val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
- return 0;
}
-static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
+static void ov9650_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
u16 id;
struct sd *sd = (struct sd *) gspca_dev;
- if (i2c_r2(gspca_dev, 0x1c, &id) < 0)
- return -EINVAL;
+ i2c_r2(gspca_dev, 0x1c, &id);
+ if (gspca_dev->usb_err < 0)
+ return;
if (id != 0x7fa2) {
pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id);
- return -ENODEV;
+ gspca_dev->usb_err = -ENODEV;
+ return;
}
- for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
- if (i2c_w1(gspca_dev, ov9650_init[i].reg,
- ov9650_init[i].val) < 0) {
- pr_err("OV9650 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("OV9650 sensor initialization failed\n");
sd->hstart = 1;
sd->vstart = 7;
- return 0;
}
-static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
+static void ov9655_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
- if (i2c_w1(gspca_dev, ov9655_init[i].reg,
- ov9655_init[i].val) < 0) {
- pr_err("OV9655 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("OV9655 sensor initialization failed\n");
+
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
sd->hstart = 1;
sd->vstart = 2;
- return 0;
}
-static int soi968_init_sensor(struct gspca_dev *gspca_dev)
+static void soi968_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
- if (i2c_w1(gspca_dev, soi968_init[i].reg,
- soi968_init[i].val) < 0) {
- pr_err("SOI968 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("SOI968 sensor initialization failed\n");
+
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX)
- | (1 << EXPOSURE_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP)
+ | (1 << EXPOSURE);
sd->hstart = 60;
sd->vstart = 11;
- return 0;
}
-static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
+static void ov7660_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
- if (i2c_w1(gspca_dev, ov7660_init[i].reg,
- ov7660_init[i].val) < 0) {
- pr_err("OV7660 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("OV7660 sensor initialization failed\n");
sd->hstart = 3;
sd->vstart = 3;
- return 0;
}
-static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
+static void ov7670_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
- if (i2c_w1(gspca_dev, ov7670_init[i].reg,
- ov7670_init[i].val) < 0) {
- pr_err("OV7670 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("OV7670 sensor initialization failed\n");
+
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
sd->hstart = 0;
sd->vstart = 1;
- return 0;
}
-static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9v_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
u16 value;
- int ret;
sd->i2c_addr = 0x5d;
- ret = i2c_r2(gspca_dev, 0xff, &value);
- if ((ret == 0) && (value == 0x8243)) {
- for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
- if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
- mt9v011_init[i].val) < 0) {
- pr_err("MT9V011 sensor initialization failed\n");
- return -ENODEV;
- }
+ i2c_r2(gspca_dev, 0xff, &value);
+ if (gspca_dev->usb_err >= 0
+ && value == 0x8243) {
+ i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init));
+ if (gspca_dev->usb_err < 0) {
+ pr_err("MT9V011 sensor initialization failed\n");
+ return;
}
sd->hstart = 2;
sd->vstart = 2;
sd->sensor = SENSOR_MT9V011;
pr_info("MT9V011 sensor detected\n");
- return 0;
+ return;
}
+ gspca_dev->usb_err = 0;
sd->i2c_addr = 0x5c;
i2c_w2(gspca_dev, 0x01, 0x0004);
- ret = i2c_r2(gspca_dev, 0xff, &value);
- if ((ret == 0) && (value == 0x823a)) {
- for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
- if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
- mt9v111_init[i].val) < 0) {
- pr_err("MT9V111 sensor initialization failed\n");
- return -ENODEV;
- }
+ i2c_r2(gspca_dev, 0xff, &value);
+ if (gspca_dev->usb_err >= 0
+ && value == 0x823a) {
+ i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init));
+ if (gspca_dev->usb_err < 0) {
+ pr_err("MT9V111 sensor initialization failed\n");
+ return;
}
- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX)
- | (1 << AUTOGAIN_IDX)
- | (1 << GAIN_IDX);
+ gspca_dev->ctrl_dis = (1 << EXPOSURE)
+ | (1 << AUTOGAIN)
+ | (1 << GAIN);
sd->hstart = 2;
sd->vstart = 2;
sd->sensor = SENSOR_MT9V111;
pr_info("MT9V111 sensor detected\n");
- return 0;
+ return;
}
+ gspca_dev->usb_err = 0;
sd->i2c_addr = 0x5d;
- ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
- if (ret < 0) {
+ i2c_w2(gspca_dev, 0xf0, 0x0000);
+ if (gspca_dev->usb_err < 0) {
+ gspca_dev->usb_err = 0;
sd->i2c_addr = 0x48;
i2c_w2(gspca_dev, 0xf0, 0x0000);
}
- ret = i2c_r2(gspca_dev, 0x00, &value);
- if ((ret == 0) && (value == 0x1229)) {
- for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
- if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
- mt9v112_init[i].val) < 0) {
- pr_err("MT9V112 sensor initialization failed\n");
- return -ENODEV;
- }
+ i2c_r2(gspca_dev, 0x00, &value);
+ if (gspca_dev->usb_err >= 0
+ && value == 0x1229) {
+ i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init));
+ if (gspca_dev->usb_err < 0) {
+ pr_err("MT9V112 sensor initialization failed\n");
+ return;
}
sd->hstart = 6;
sd->vstart = 2;
sd->sensor = SENSOR_MT9V112;
pr_info("MT9V112 sensor detected\n");
- return 0;
+ return;
}
- return -ENODEV;
+ gspca_dev->usb_err = -ENODEV;
}
-static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m112_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
- for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
- if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
- mt9m112_init[i].val) < 0) {
- pr_err("MT9M112 sensor initialization failed\n");
- return -ENODEV;
- }
- }
- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
- | (1 << GAIN_IDX);
+
+ i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("MT9M112 sensor initialization failed\n");
+
+ gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
+ | (1 << GAIN);
sd->hstart = 0;
sd->vstart = 2;
- return 0;
}
-static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m111_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
- for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
- if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
- mt9m111_init[i].val) < 0) {
- pr_err("MT9M111 sensor initialization failed\n");
- return -ENODEV;
- }
- }
- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
- | (1 << GAIN_IDX);
+
+ i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("MT9M111 sensor initialization failed\n");
+
+ gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
+ | (1 << GAIN);
sd->hstart = 0;
sd->vstart = 2;
- return 0;
}
-static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m001_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
u16 id;
- if (i2c_r2(gspca_dev, 0x00, &id) < 0)
- return -EINVAL;
+ i2c_r2(gspca_dev, 0x00, &id);
+ if (gspca_dev->usb_err < 0)
+ return;
/* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
switch (id) {
@@ -1494,85 +1462,78 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
break;
default:
pr_err("No MT9M001 chip detected, ID = %x\n\n", id);
- return -ENODEV;
+ gspca_dev->usb_err = -ENODEV;
+ return;
}
- for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
- if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
- mt9m001_init[i].val) < 0) {
- pr_err("MT9M001 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("MT9M001 sensor initialization failed\n");
+
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
sd->hstart = 1;
sd->vstart = 1;
- return 0;
}
-static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
+static void hv7131r_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
- if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
- hv7131r_init[i].val) < 0) {
- pr_err("HV7131R Sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("HV7131R Sensor initialization failed\n");
+
sd->hstart = 0;
sd->vstart = 1;
- return 0;
}
-static int set_cmatrix(struct gspca_dev *gspca_dev)
+static void set_cmatrix(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 hue_coord, hue_index = 180 + sd->hue;
+ int satur;
+ s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val;
u8 cmatrix[21];
memset(cmatrix, 0, sizeof cmatrix);
- cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
+ cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26;
cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
- cmatrix[18] = sd->brightness - 0x80;
+ cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80;
- hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
+ satur = sd->ctrls[SATURATION].val;
+ hue_coord = (hsv_red_x[hue_index] * satur) >> 8;
cmatrix[6] = hue_coord;
cmatrix[7] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_red_y[hue_index] * satur) >> 8;
cmatrix[8] = hue_coord;
cmatrix[9] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_green_x[hue_index] * satur) >> 8;
cmatrix[10] = hue_coord;
cmatrix[11] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_green_y[hue_index] * satur) >> 8;
cmatrix[12] = hue_coord;
cmatrix[13] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_blue_x[hue_index] * satur) >> 8;
cmatrix[14] = hue_coord;
cmatrix[15] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_blue_y[hue_index] * satur) >> 8;
cmatrix[16] = hue_coord;
cmatrix[17] = (hue_coord >> 8) & 0x0f;
- return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
+ reg_w(gspca_dev, 0x10e1, cmatrix, 21);
}
-static int set_gamma(struct gspca_dev *gspca_dev)
+static void set_gamma(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 gamma[17];
- u8 gval = sd->gamma * 0xb8 / 0x100;
-
+ u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100;
gamma[0] = 0x0a;
gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
@@ -1592,29 +1553,29 @@ static int set_gamma(struct gspca_dev *gspca_dev)
gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
gamma[16] = 0xf5;
- return reg_w(gspca_dev, 0x1190, gamma, 17);
+ reg_w(gspca_dev, 0x1190, gamma, 17);
}
-static int set_redblue(struct gspca_dev *gspca_dev)
+static void set_redblue(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- reg_w1(gspca_dev, 0x118c, sd->red);
- reg_w1(gspca_dev, 0x118f, sd->blue);
- return 0;
+
+ reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val);
+ reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val);
}
-static int set_hvflip(struct gspca_dev *gspca_dev)
+static void set_hvflip(struct gspca_dev *gspca_dev)
{
u8 value, tslb, hflip, vflip;
u16 value2;
struct sd *sd = (struct sd *) gspca_dev;
if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
- hflip = !sd->hflip;
- vflip = !sd->vflip;
+ hflip = !sd->ctrls[HFLIP].val;
+ vflip = !sd->ctrls[VFLIP].val;
} else {
- hflip = sd->hflip;
- vflip = sd->vflip;
+ hflip = sd->ctrls[HFLIP].val;
+ vflip = sd->ctrls[VFLIP].val;
}
switch (sd->sensor) {
@@ -1625,8 +1586,9 @@ static int set_hvflip(struct gspca_dev *gspca_dev)
if (vflip) {
value |= 0x10;
sd->vstart = 2;
- } else
+ } else {
sd->vstart = 3;
+ }
reg_w1(gspca_dev, 0x1182, sd->vstart);
i2c_w1(gspca_dev, 0x1e, value);
break;
@@ -1674,13 +1636,15 @@ static int set_hvflip(struct gspca_dev *gspca_dev)
i2c_w1(gspca_dev, 0x01, value);
break;
}
- return 0;
}
-static int set_exposure(struct gspca_dev *gspca_dev)
+static void set_exposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
+ int expo;
+
+ expo = sd->ctrls[EXPOSURE].val;
switch (sd->sensor) {
case SENSOR_OV7660:
case SENSOR_OV7670:
@@ -1688,35 +1652,37 @@ static int set_exposure(struct gspca_dev *gspca_dev)
case SENSOR_OV9650:
exp[0] |= (3 << 4);
exp[2] = 0x2d;
- exp[3] = sd->exposure & 0xff;
- exp[4] = sd->exposure >> 8;
+ exp[3] = expo;
+ exp[4] = expo >> 8;
break;
case SENSOR_MT9M001:
case SENSOR_MT9V112:
case SENSOR_MT9V011:
exp[0] |= (3 << 4);
exp[2] = 0x09;
- exp[3] = sd->exposure >> 8;
- exp[4] = sd->exposure & 0xff;
+ exp[3] = expo >> 8;
+ exp[4] = expo;
break;
case SENSOR_HV7131R:
exp[0] |= (4 << 4);
exp[2] = 0x25;
- exp[3] = (sd->exposure >> 5) & 0xff;
- exp[4] = (sd->exposure << 3) & 0xff;
+ exp[3] = expo >> 5;
+ exp[4] = expo << 3;
exp[5] = 0;
break;
default:
- return 0;
+ return;
}
i2c_w(gspca_dev, exp);
- return 0;
}
-static int set_gain(struct gspca_dev *gspca_dev)
+static void set_gain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
+ int g;
+
+ g = sd->ctrls[GAIN].val;
switch (sd->sensor) {
case SENSOR_OV7660:
case SENSOR_OV7670:
@@ -1724,238 +1690,50 @@ static int set_gain(struct gspca_dev *gspca_dev)
case SENSOR_OV9655:
case SENSOR_OV9650:
gain[0] |= (2 << 4);
- gain[3] = ov_gain[sd->gain];
+ gain[3] = ov_gain[g];
break;
case SENSOR_MT9V011:
gain[0] |= (3 << 4);
gain[2] = 0x35;
- gain[3] = micron1_gain[sd->gain] >> 8;
- gain[4] = micron1_gain[sd->gain] & 0xff;
+ gain[3] = micron1_gain[g] >> 8;
+ gain[4] = micron1_gain[g];
break;
case SENSOR_MT9V112:
gain[0] |= (3 << 4);
gain[2] = 0x2f;
- gain[3] = micron1_gain[sd->gain] >> 8;
- gain[4] = micron1_gain[sd->gain] & 0xff;
+ gain[3] = micron1_gain[g] >> 8;
+ gain[4] = micron1_gain[g];
break;
case SENSOR_MT9M001:
gain[0] |= (3 << 4);
gain[2] = 0x2f;
- gain[3] = micron2_gain[sd->gain] >> 8;
- gain[4] = micron2_gain[sd->gain] & 0xff;
+ gain[3] = micron2_gain[g] >> 8;
+ gain[4] = micron2_gain[g];
break;
case SENSOR_HV7131R:
gain[0] |= (2 << 4);
gain[2] = 0x30;
- gain[3] = hv7131r_gain[sd->gain];
+ gain[3] = hv7131r_gain[g];
break;
default:
- return 0;
+ return;
}
i2c_w(gspca_dev, gain);
- return 0;
-}
-
-static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->brightness = val;
- if (gspca_dev->streaming)
- return set_cmatrix(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)
- return set_cmatrix(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_setsaturation(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->saturation = val;
- if (gspca_dev->streaming)
- return set_cmatrix(gspca_dev);
- return 0;
}
-static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
+static void set_quality(struct gspca_dev *gspca_dev)
{
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)
- return set_cmatrix(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_setgamma(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gamma = val;
- if (gspca_dev->streaming)
- return set_gamma(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_setredbalance(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->red = val;
- if (gspca_dev->streaming)
- return set_redblue(gspca_dev);
- return 0;
-}
-
-static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->red;
- return 0;
-}
-
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->blue = val;
- if (gspca_dev->streaming)
- return set_redblue(gspca_dev);
- return 0;
-}
-
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->blue;
- return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->hflip = val;
- if (gspca_dev->streaming)
- return set_hvflip(gspca_dev);
- return 0;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->hflip;
- 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)
- return set_hvflip(gspca_dev);
- 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_setexposure(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->exposure = val;
- if (gspca_dev->streaming)
- return set_exposure(gspca_dev);
- return 0;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->exposure;
- return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gain = val;
- if (gspca_dev->streaming)
- return set_gain(gspca_dev);
- return 0;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->gain;
- return 0;
-}
-
-static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- sd->auto_exposure = val;
- return 0;
-}
-static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->auto_exposure;
- return 0;
+ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+ reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */
+ reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */
+ reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
+ reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
+ reg_w1(gspca_dev, 0x1061, 0x03); /* restart transfer */
+ reg_w1(gspca_dev, 0x10e0, sd->fmt);
+ sd->fmt ^= 0x0c; /* invert QTAB use + write */
+ reg_w1(gspca_dev, 0x10e0, sd->fmt);
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1963,28 +1741,26 @@ static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
struct v4l2_dbg_register *reg)
{
struct sd *sd = (struct sd *) gspca_dev;
+
switch (reg->match.type) {
case V4L2_CHIP_MATCH_HOST:
if (reg->match.addr != 0)
return -EINVAL;
if (reg->reg < 0x1000 || reg->reg > 0x11ff)
return -EINVAL;
- if (reg_r(gspca_dev, reg->reg, 1) < 0)
- return -EINVAL;
+ reg_r(gspca_dev, reg->reg, 1);
reg->val = gspca_dev->usb_buf[0];
- return 0;
+ return gspca_dev->usb_err;
case V4L2_CHIP_MATCH_I2C_ADDR:
if (reg->match.addr != sd->i2c_addr)
return -EINVAL;
if (sd->sensor >= SENSOR_MT9V011 &&
sd->sensor <= SENSOR_MT9M112) {
- if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
- return -EINVAL;
+ i2c_r2(gspca_dev, reg->reg, (u16 *) &reg->val);
} else {
- if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
- return -EINVAL;
+ i2c_r1(gspca_dev, reg->reg, (u8 *) &reg->val);
}
- return 0;
+ return gspca_dev->usb_err;
}
return -EINVAL;
}
@@ -1993,27 +1769,25 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
struct v4l2_dbg_register *reg)
{
struct sd *sd = (struct sd *) gspca_dev;
+
switch (reg->match.type) {
case V4L2_CHIP_MATCH_HOST:
if (reg->match.addr != 0)
return -EINVAL;
if (reg->reg < 0x1000 || reg->reg > 0x11ff)
return -EINVAL;
- if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
- return -EINVAL;
- return 0;
+ reg_w1(gspca_dev, reg->reg, reg->val);
+ return gspca_dev->usb_err;
case V4L2_CHIP_MATCH_I2C_ADDR:
if (reg->match.addr != sd->i2c_addr)
return -EINVAL;
if (sd->sensor >= SENSOR_MT9V011 &&
sd->sensor <= SENSOR_MT9M112) {
- if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
- return -EINVAL;
+ i2c_w2(gspca_dev, reg->reg, reg->val);
} else {
- if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
- return -EINVAL;
+ i2c_w1(gspca_dev, reg->reg, reg->val);
}
- return 0;
+ return gspca_dev->usb_err;
}
return -EINVAL;
}
@@ -2050,9 +1824,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->needs_full_bandwidth = 1;
- sd->sensor = (id->driver_info >> 8) & 0xff;
- sd->i2c_addr = id->driver_info & 0xff;
- sd->flags = (id->driver_info >> 16) & 0xff;
+ sd->sensor = id->driver_info >> 8;
+ sd->i2c_addr = id->driver_info;
+ sd->flags = id->driver_info >> 16;
switch (sd->sensor) {
case SENSOR_MT9M112:
@@ -2076,21 +1850,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->older_step = 0;
sd->exposure_step = 16;
- sd->brightness = BRIGHTNESS_DEFAULT;
- sd->contrast = CONTRAST_DEFAULT;
- sd->saturation = SATURATION_DEFAULT;
- sd->hue = HUE_DEFAULT;
- sd->gamma = GAMMA_DEFAULT;
- sd->red = RED_DEFAULT;
- sd->blue = BLUE_DEFAULT;
+ gspca_dev->cam.ctrls = sd->ctrls;
- sd->hflip = HFLIP_DEFAULT;
- sd->vflip = VFLIP_DEFAULT;
- sd->exposure = EXPOSURE_DEFAULT;
- sd->gain = GAIN_DEFAULT;
- sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
-
- sd->quality = 95;
+ INIT_WORK(&sd->work, qual_upd);
return 0;
}
@@ -2105,9 +1867,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
value = bridge_init[i][1];
- if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
+ reg_w(gspca_dev, bridge_init[i][0], &value, 1);
+ if (gspca_dev->usb_err < 0) {
pr_err("Device initialization failed\n");
- return -ENODEV;
+ return gspca_dev->usb_err;
}
}
@@ -2116,72 +1879,85 @@ static int sd_init(struct gspca_dev *gspca_dev)
else
reg_w1(gspca_dev, 0x1006, 0x20);
- if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
+ reg_w(gspca_dev, 0x10c0, i2c_init, 9);
+ if (gspca_dev->usb_err < 0) {
pr_err("Device initialization failed\n");
- return -ENODEV;
+ return gspca_dev->usb_err;
}
switch (sd->sensor) {
case SENSOR_OV9650:
- if (ov9650_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ ov9650_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("OV9650 sensor detected\n");
break;
case SENSOR_OV9655:
- if (ov9655_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ ov9655_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("OV9655 sensor detected\n");
break;
case SENSOR_SOI968:
- if (soi968_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ soi968_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("SOI968 sensor detected\n");
break;
case SENSOR_OV7660:
- if (ov7660_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ ov7660_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("OV7660 sensor detected\n");
break;
case SENSOR_OV7670:
- if (ov7670_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ ov7670_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("OV7670 sensor detected\n");
break;
case SENSOR_MT9VPRB:
- if (mt9v_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ mt9v_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
+ pr_info("MT9VPRB sensor detected\n");
break;
case SENSOR_MT9M111:
- if (mt9m111_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ mt9m111_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("MT9M111 sensor detected\n");
break;
case SENSOR_MT9M112:
- if (mt9m112_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ mt9m112_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("MT9M112 sensor detected\n");
break;
case SENSOR_MT9M001:
- if (mt9m001_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ mt9m001_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
break;
case SENSOR_HV7131R:
- if (hv7131r_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ hv7131r_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("HV7131R sensor detected\n");
break;
default:
- pr_info("Unsupported Sensor\n");
- return -ENODEV;
+ pr_err("Unsupported sensor\n");
+ gspca_dev->usb_err = -ENODEV;
}
- return 0;
+ return gspca_dev->usb_err;
}
static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 value;
+
switch (sd->sensor) {
case SENSOR_SOI968:
if (mode & MODE_SXGA) {
@@ -2264,6 +2040,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
break;
default: /* >= 640x480 */
gspca_dev->alt = 9;
+ break;
}
}
@@ -2290,14 +2067,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
jpeg_define(sd->jpeg_hdr, height, width,
0x21);
- jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
if (mode & MODE_RAW)
fmt = 0x2d;
else if (mode & MODE_JPEG)
- fmt = 0x2c;
+ fmt = 0x24;
else
fmt = 0x2f; /* YUV 420 */
+ sd->fmt = fmt;
switch (mode & SCALE_MASK) {
case SCALE_1280x1024:
@@ -2334,18 +2112,37 @@ static int sd_start(struct gspca_dev *gspca_dev)
set_hvflip(gspca_dev);
reg_w1(gspca_dev, 0x1007, 0x20);
+ reg_w1(gspca_dev, 0x1061, 0x03);
+
+ /* if JPEG, prepare the compression quality update */
+ if (mode & MODE_JPEG) {
+ sd->pktsz = sd->npkt = 0;
+ sd->nchg = 0;
+ sd->work_thread =
+ create_singlethread_workqueue(KBUILD_MODNAME);
+ }
- reg_r(gspca_dev, 0x1061, 1);
- reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
- return 0;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
reg_w1(gspca_dev, 0x1007, 0x00);
+ reg_w1(gspca_dev, 0x1061, 0x01);
+}
+
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
- reg_r(gspca_dev, 0x1061, 1);
- reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
+ if (sd->work_thread != NULL) {
+ mutex_unlock(&gspca_dev->usb_lock);
+ destroy_workqueue(sd->work_thread);
+ mutex_lock(&gspca_dev->usb_lock);
+ sd->work_thread = NULL;
+ }
}
static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
@@ -2359,15 +2156,15 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
* and exposure steps
*/
if (avg_lum < MIN_AVG_LUM) {
- if (sd->exposure > 0x1770)
+ if (sd->ctrls[EXPOSURE].val > 0x1770)
return;
- new_exp = sd->exposure + sd->exposure_step;
+ new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step;
if (new_exp > 0x1770)
new_exp = 0x1770;
if (new_exp < 0x10)
new_exp = 0x10;
- sd->exposure = new_exp;
+ sd->ctrls[EXPOSURE].val = new_exp;
set_exposure(gspca_dev);
sd->older_step = sd->old_step;
@@ -2379,14 +2176,14 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
sd->exposure_step += 2;
}
if (avg_lum > MAX_AVG_LUM) {
- if (sd->exposure < 0x10)
+ if (sd->ctrls[EXPOSURE].val < 0x10)
return;
- new_exp = sd->exposure - sd->exposure_step;
+ new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step;
if (new_exp > 0x1700)
new_exp = 0x1770;
if (new_exp < 0x10)
new_exp = 0x10;
- sd->exposure = new_exp;
+ sd->ctrls[EXPOSURE].val = new_exp;
set_exposure(gspca_dev);
sd->older_step = sd->old_step;
sd->old_step = 0;
@@ -2403,14 +2200,14 @@ static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
struct sd *sd = (struct sd *) gspca_dev;
if (avg_lum < MIN_AVG_LUM) {
- if (sd->gain + 1 <= 28) {
- sd->gain++;
+ if (sd->ctrls[GAIN].val + 1 <= 28) {
+ sd->ctrls[GAIN].val++;
set_gain(gspca_dev);
}
}
if (avg_lum > MAX_AVG_LUM) {
- if (sd->gain > 0) {
- sd->gain--;
+ if (sd->ctrls[GAIN].val > 0) {
+ sd->ctrls[GAIN].val--;
set_gain(gspca_dev);
}
}
@@ -2421,7 +2218,7 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int avg_lum;
- if (!sd->auto_exposure)
+ if (!sd->ctrls[AUTOGAIN].val)
return;
avg_lum = atomic_read(&sd->avg_lum);
@@ -2431,33 +2228,92 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
do_autoexposure(gspca_dev, avg_lum);
}
+/* JPEG quality update */
+/* This function is executed from a work queue. */
+static void qual_upd(struct work_struct *work)
+{
+ struct sd *sd = container_of(work, struct sd, work);
+ struct gspca_dev *gspca_dev = &sd->gspca_dev;
+
+ mutex_lock(&gspca_dev->usb_lock);
+ PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val);
+ set_quality(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+}
+
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet */
int len) /* interrupt packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret = -EINVAL;
+
if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
- input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
- input_sync(gspca_dev->input_dev);
- input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
- input_sync(gspca_dev->input_dev);
- ret = 0;
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+ input_sync(gspca_dev->input_dev);
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ return 0;
}
- return ret;
+ return -EINVAL;
}
#endif
+/* check the JPEG compression */
+static void transfer_check(struct gspca_dev *gspca_dev,
+ u8 *data)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int new_qual, r;
+
+ new_qual = 0;
+
+ /* if USB error, discard the frame and decrease the quality */
+ if (data[6] & 0x08) { /* USB FIFO full */
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ new_qual = -5;
+ } else {
+
+ /* else, compute the filling rate and a new JPEG quality */
+ r = (sd->pktsz * 100) /
+ (sd->npkt *
+ gspca_dev->urb[0]->iso_frame_desc[0].length);
+ if (r >= 85)
+ new_qual = -3;
+ else if (r < 75)
+ new_qual = 2;
+ }
+ if (new_qual != 0) {
+ sd->nchg += new_qual;
+ if (sd->nchg < -6 || sd->nchg >= 12) {
+ sd->nchg = 0;
+ new_qual += sd->ctrls[QUALITY].val;
+ if (new_qual < QUALITY_MIN)
+ new_qual = QUALITY_MIN;
+ else if (new_qual > QUALITY_MAX)
+ new_qual = QUALITY_MAX;
+ if (new_qual != sd->ctrls[QUALITY].val) {
+ sd->ctrls[QUALITY].val = new_qual;
+ queue_work(sd->work_thread, &sd->work);
+ }
+ }
+ } else {
+ sd->nchg = 0;
+ }
+ sd->pktsz = sd->npkt = 0;
+}
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
- int avg_lum;
+ int avg_lum, is_jpeg;
static u8 frame_header[] =
{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
- if (len == 64 && memcmp(data, frame_header, 6) == 0) {
+
+ is_jpeg = (sd->fmt & 0x03) == 0;
+ if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
avg_lum = ((data[35] >> 2) & 3) |
(data[20] << 2) |
(data[19] << 10);
@@ -2484,12 +2340,18 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
(data[33] << 10);
avg_lum >>= 9;
atomic_set(&sd->avg_lum, avg_lum);
+
+ if (is_jpeg)
+ transfer_check(gspca_dev, data);
+
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
- return;
+ len -= 64;
+ if (len == 0)
+ return;
+ data += 64;
}
if (gspca_dev->last_packet_type == LAST_PACKET) {
- if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
- & MODE_JPEG) {
+ if (is_jpeg) {
gspca_frame_add(gspca_dev, FIRST_PACKET,
sd->jpeg_hdr, JPEG_HDR_SZ);
gspca_frame_add(gspca_dev, INTER_PACKET,
@@ -2499,13 +2361,18 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data, len);
}
} else {
+ /* if JPEG, count the packets and their size */
+ if (is_jpeg) {
+ sd->npkt++;
+ sd->pktsz += len;
+ }
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
}
/* sub-driver description */
static const struct sd_desc sd_desc = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
@@ -2513,6 +2380,7 @@ static const struct sd_desc sd_desc = {
.isoc_init = sd_isoc_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
@@ -2581,7 +2449,7 @@ static int sd_probe(struct usb_interface *intf,
}
static struct usb_driver sd_driver = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,