diff options
Diffstat (limited to 'drivers/media/video/gspca/sn9c20x.c')
-rw-r--r-- | drivers/media/video/gspca/sn9c20x.c | 1138 |
1 files changed, 503 insertions, 635 deletions
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index 9e198b45c3c..7e71aa2d252 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 *)®->val) < 0) - return -EINVAL; + i2c_r2(gspca_dev, reg->reg, (u16 *) ®->val); } else { - if (i2c_r1(gspca_dev, reg->reg, (u8 *)®->val) < 0) - return -EINVAL; + i2c_r1(gspca_dev, reg->reg, (u8 *) ®->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, |