diff options
Diffstat (limited to 'drivers/media/video/gspca/pac7302.c')
-rw-r--r-- | drivers/media/video/gspca/pac7302.c | 411 |
1 files changed, 188 insertions, 223 deletions
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index de0b66c4b56..2a68220d1ad 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c @@ -4,7 +4,9 @@ * * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> * - * Separated from Pixart PAC7311 library by Márton Németh <nm127@freemail.hu> + * Separated from Pixart PAC7311 library by Márton Németh + * Camera button input handling by Márton Németh <nm127@freemail.hu> + * Copyright (C) 2009-2010 Márton Németh <nm127@freemail.hu> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,33 +24,26 @@ */ /* Some documentation about various registers as determined by trial and error. - When the register addresses differ between the 7202 and the 7311 the 2 - different addresses are written as 7302addr/7311addr, when one of the 2 - addresses is a - sign that register description is not valid for the - matching IC. Register page 1: Address Description - -/0x08 Unknown compressor related, must always be 8 except when not - in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 ! - -/0x1b Auto white balance related, bit 0 is AWB enable (inverted) - bits 345 seem to toggle per color gains on/off (inverted) 0x78 Global control, bit 6 controls the LED (inverted) - -/0x80 JPEG compression ratio ? Best not touched - Register page 3/4: + Register page 3: Address Description - 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on + 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? - -/0x0f Master gain 1-245, low value = high gain - 0x10/- Master gain 0-31 - -/0x10 Another gain 0-15, limited influence (1-2x gain I guess) + 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps + 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps, + 63 -> ~27 fps, the 2 msb's must always be 1 !! + 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0: + 1 -> ~30 fps, 2 -> ~20 fps + 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time + 0x0f Exposure bit 8, 0-448, 448 = no exposure at all + 0x10 Master gain 0-31 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused - -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to - completely disable the analog amplification block. Set to 0x68 - for max gain, 0x14 for minimal gain. The registers are accessed in the following functions: @@ -68,6 +63,7 @@ #define MODULE_NAME "pac7302" +#include <linux/input.h> #include <media/v4l2-chip-ident.h> #include "gspca.h" @@ -86,8 +82,8 @@ struct sd { unsigned char red_balance; unsigned char blue_balance; unsigned char gain; - unsigned char exposure; unsigned char autogain; + unsigned short exposure; __u8 hflip; __u8 vflip; u8 flags; @@ -124,8 +120,7 @@ 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 struct ctrl sd_ctrls[] = { -/* This control is pac7302 only */ +static const struct ctrl sd_ctrls[] = { { { .id = V4L2_CID_BRIGHTNESS, @@ -141,7 +136,6 @@ static struct ctrl sd_ctrls[] = { .set = sd_setbrightness, .get = sd_getbrightness, }, -/* This control is for both the 7302 and the 7311 */ { { .id = V4L2_CID_CONTRAST, @@ -157,7 +151,6 @@ static struct ctrl sd_ctrls[] = { .set = sd_setcontrast, .get = sd_getcontrast, }, -/* This control is pac7302 only */ { { .id = V4L2_CID_SATURATION, @@ -215,7 +208,6 @@ static struct ctrl sd_ctrls[] = { .set = sd_setbluebalance, .get = sd_getbluebalance, }, -/* All controls below are for both the 7302 and the 7311 */ { { .id = V4L2_CID_GAIN, @@ -238,11 +230,10 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Exposure", .minimum = 0, -#define EXPOSURE_MAX 255 - .maximum = EXPOSURE_MAX, + .maximum = 1023, .step = 1, -#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */ -#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */ +#define EXPOSURE_DEF 66 /* 33 ms / 30 fps */ +#define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ .default_value = EXPOSURE_DEF, }, .set = sd_setexposure, @@ -301,7 +292,6 @@ static const struct v4l2_pix_format vga_mode[] = { }; #define LOAD_PAGE3 255 -#define LOAD_PAGE4 254 #define END_OF_SEQUENCE 0 /* pac 7302 */ @@ -379,7 +369,7 @@ static const __u8 start_7302[] = { #define SKIP 0xaa /* page 3 - the value SKIP says skip the index - see reg_w_page() */ static const __u8 page3_7302[] = { - 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16, + 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16, 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00, @@ -388,7 +378,7 @@ static const __u8 page3_7302[] = { 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00, + SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -401,12 +391,14 @@ static const __u8 page3_7302[] = { 0x00 }; -static int reg_w_buf(struct gspca_dev *gspca_dev, +static void reg_w_buf(struct gspca_dev *gspca_dev, __u8 index, const char *buffer, int len) { int ret; + if (gspca_dev->usb_err < 0) + return; memcpy(gspca_dev->usb_buf, buffer, len); ret = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), @@ -415,20 +407,23 @@ static int reg_w_buf(struct gspca_dev *gspca_dev, 0, /* value */ index, gspca_dev->usb_buf, len, 500); - if (ret < 0) + if (ret < 0) { PDEBUG(D_ERR, "reg_w_buf(): " "Failed to write registers to index 0x%x, error %i", index, ret); - return ret; + gspca_dev->usb_err = ret; + } } -static int reg_w(struct gspca_dev *gspca_dev, +static void reg_w(struct gspca_dev *gspca_dev, __u8 index, __u8 value) { int ret; + if (gspca_dev->usb_err < 0) + return; gspca_dev->usb_buf[0] = value; ret = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), @@ -436,32 +431,32 @@ static int reg_w(struct gspca_dev *gspca_dev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, index, gspca_dev->usb_buf, 1, 500); - if (ret < 0) + if (ret < 0) { PDEBUG(D_ERR, "reg_w(): " "Failed to write register to index 0x%x, value 0x%x, error %i", index, value, ret); - return ret; + gspca_dev->usb_err = ret; + } } -static int reg_w_seq(struct gspca_dev *gspca_dev, +static void reg_w_seq(struct gspca_dev *gspca_dev, const __u8 *seq, int len) { - int ret = 0; while (--len >= 0) { - if (0 <= ret) - ret = reg_w(gspca_dev, seq[0], seq[1]); + reg_w(gspca_dev, seq[0], seq[1]); seq += 2; } - return ret; } /* load the beginning of a page */ -static int reg_w_page(struct gspca_dev *gspca_dev, +static void reg_w_page(struct gspca_dev *gspca_dev, const __u8 *page, int len) { int index; int ret = 0; + if (gspca_dev->usb_err < 0) + return; for (index = 0; index < len; index++) { if (page[index] == SKIP) /* skip this index */ continue; @@ -477,56 +472,47 @@ static int reg_w_page(struct gspca_dev *gspca_dev, "Failed to write register to index 0x%x, " "value 0x%x, error %i", index, page[index], ret); + gspca_dev->usb_err = ret; break; } } - return ret; } /* output a variable sequence */ -static int reg_w_var(struct gspca_dev *gspca_dev, +static void reg_w_var(struct gspca_dev *gspca_dev, const __u8 *seq, - const __u8 *page3, unsigned int page3_len, - const __u8 *page4, unsigned int page4_len) + const __u8 *page3, unsigned int page3_len) { int index, len; - int ret = 0; for (;;) { index = *seq++; len = *seq++; switch (len) { case END_OF_SEQUENCE: - return ret; - case LOAD_PAGE4: - ret = reg_w_page(gspca_dev, page4, page4_len); - break; + return; case LOAD_PAGE3: - ret = reg_w_page(gspca_dev, page3, page3_len); + reg_w_page(gspca_dev, page3, page3_len); break; default: if (len > USB_BUF_SZ) { PDEBUG(D_ERR|D_STREAM, "Incorrect variable sequence"); - return -EINVAL; + return; } while (len > 0) { if (len < 8) { - ret = reg_w_buf(gspca_dev, + reg_w_buf(gspca_dev, index, seq, len); - if (ret < 0) - return ret; seq += len; break; } - ret = reg_w_buf(gspca_dev, index, seq, 8); + reg_w_buf(gspca_dev, index, seq, 8); seq += 8; index += 8; len -= 8; } } - if (ret < 0) - return ret; } /* not reached */ } @@ -560,11 +546,10 @@ static int sd_config(struct gspca_dev *gspca_dev, } /* This function is used by pac7302 only */ -static int setbrightcont(struct gspca_dev *gspca_dev) +static void setbrightcont(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int i, v; - int ret; static const __u8 max[10] = {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb, 0xd4, 0xec}; @@ -572,7 +557,7 @@ static int setbrightcont(struct gspca_dev *gspca_dev) {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17, 0x11, 0x0b}; - ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ for (i = 0; i < 10; i++) { v = max[i]; v += (sd->brightness - BRIGHTNESS_MAX) @@ -582,136 +567,121 @@ static int setbrightcont(struct gspca_dev *gspca_dev) v = 0; else if (v > 0xff) v = 0xff; - if (0 <= ret) - ret = reg_w(gspca_dev, 0xa2 + i, v); + reg_w(gspca_dev, 0xa2 + i, v); } - if (0 <= ret) - ret = reg_w(gspca_dev, 0xdc, 0x01); - return ret; + reg_w(gspca_dev, 0xdc, 0x01); } /* This function is used by pac7302 only */ -static int setcolors(struct gspca_dev *gspca_dev) +static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int i, v; - int ret; static const int a[9] = {217, -212, 0, -101, 170, -67, -38, -315, 355}; static const int b[9] = {19, 106, 0, 19, 106, 1, 19, 106, 1}; - ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ - if (0 <= ret) - ret = reg_w(gspca_dev, 0x11, 0x01); - if (0 <= ret) - ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + reg_w(gspca_dev, 0x11, 0x01); + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ for (i = 0; i < 9; i++) { v = a[i] * sd->colors / COLOR_MAX + b[i]; - if (0 <= ret) - ret = reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); - if (0 <= ret) - ret = reg_w(gspca_dev, 0x0f + 2 * i + 1, v); + reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); + reg_w(gspca_dev, 0x0f + 2 * i + 1, v); } - if (0 <= ret) - ret = reg_w(gspca_dev, 0xdc, 0x01); + reg_w(gspca_dev, 0xdc, 0x01); PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); - return ret; } -static int setwhitebalance(struct gspca_dev *gspca_dev) +static void setwhitebalance(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int ret; - ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - if (0 <= ret) - ret = reg_w(gspca_dev, 0xc6, sd->white_balance); + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, 0xc6, sd->white_balance); - if (0 <= ret) - ret = reg_w(gspca_dev, 0xdc, 0x01); + reg_w(gspca_dev, 0xdc, 0x01); PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance); - return ret; } -static int setredbalance(struct gspca_dev *gspca_dev) +static void setredbalance(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int ret; - ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - if (0 <= ret) - ret = reg_w(gspca_dev, 0xc5, sd->red_balance); + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, 0xc5, sd->red_balance); - if (0 <= ret) - ret = reg_w(gspca_dev, 0xdc, 0x01); + reg_w(gspca_dev, 0xdc, 0x01); PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance); - return ret; } -static int setbluebalance(struct gspca_dev *gspca_dev) +static void setbluebalance(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int ret; - ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - if (0 <= ret) - ret = reg_w(gspca_dev, 0xc7, sd->blue_balance); + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, 0xc7, sd->blue_balance); - if (0 <= ret) - ret = reg_w(gspca_dev, 0xdc, 0x01); + reg_w(gspca_dev, 0xdc, 0x01); PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance); - return ret; } -static int setgain(struct gspca_dev *gspca_dev) +static void setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int ret; - ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ - if (0 <= ret) - ret = reg_w(gspca_dev, 0x10, sd->gain >> 3); + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + reg_w(gspca_dev, 0x10, sd->gain >> 3); /* load registers to sensor (Bit 0, auto clear) */ - if (0 <= ret) - ret = reg_w(gspca_dev, 0x11, 0x01); - return ret; + reg_w(gspca_dev, 0x11, 0x01); } -static int setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int ret; - __u8 reg; - - /* register 2 of frame 3/4 contains the clock divider configuring the - no fps according to the formula: 60 / reg. sd->exposure is the - desired exposure time in ms. */ - reg = 120 * sd->exposure / 1000; - if (reg < 2) - reg = 2; - else if (reg > 63) - reg = 63; - - /* On the pac7302 reg2 MUST be a multiple of 3, so round it to - the nearest multiple of 3, except when between 6 and 12? */ - if (reg < 6 || reg > 12) - reg = ((reg + 1) / 3) * 3; - ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ - if (0 <= ret) - ret = reg_w(gspca_dev, 0x02, reg); + __u8 clockdiv; + __u16 exposure; + + /* register 2 of frame 3 contains the clock divider configuring the + no fps according to the formula: 90 / reg. sd->exposure is the + desired exposure time in 0.5 ms. */ + clockdiv = (90 * sd->exposure + 1999) / 2000; + + /* Note clockdiv = 3 also works, but when running at 30 fps, depending + on the scene being recorded, the camera switches to another + quantization table for certain JPEG blocks, and we don't know how + to decompress these blocks. So we cap the framerate at 15 fps */ + if (clockdiv < 6) + clockdiv = 6; + else if (clockdiv > 63) + clockdiv = 63; + + /* reg2 MUST be a multiple of 3, except when between 6 and 12? + Always round up, otherwise we cannot get the desired frametime + using the partial frame time exposure control */ + if (clockdiv < 6 || clockdiv > 12) + clockdiv = ((clockdiv + 2) / 3) * 3; + + /* frame exposure time in ms = 1000 * clockdiv / 90 -> + exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */ + exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv); + /* 0 = use full frametime, 448 = no exposure, reverse it */ + exposure = 448 - exposure; + + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + reg_w(gspca_dev, 0x02, clockdiv); + reg_w(gspca_dev, 0x0e, exposure & 0xff); + reg_w(gspca_dev, 0x0f, exposure >> 8); /* load registers to sensor (Bit 0, auto clear) */ - if (0 <= ret) - ret = reg_w(gspca_dev, 0x11, 0x01); - return ret; + reg_w(gspca_dev, 0x11, 0x01); } -static int sethvflip(struct gspca_dev *gspca_dev) +static void sethvflip(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int ret; u8 data, hflip, vflip; hflip = sd->hflip; @@ -721,48 +691,37 @@ static int sethvflip(struct gspca_dev *gspca_dev) if (sd->flags & FL_VFLIP) vflip = !vflip; - ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00); - if (0 <= ret) - ret = reg_w(gspca_dev, 0x21, data); + reg_w(gspca_dev, 0x21, data); + /* load registers to sensor (Bit 0, auto clear) */ - if (0 <= ret) - ret = reg_w(gspca_dev, 0x11, 0x01); - return ret; + reg_w(gspca_dev, 0x11, 0x01); } /* this function is called at probe and resume time for pac7302 */ static int sd_init(struct gspca_dev *gspca_dev) { - return reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2); + reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2); + return gspca_dev->usb_err; } static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int ret = 0; sd->sof_read = 0; - ret = reg_w_var(gspca_dev, start_7302, - page3_7302, sizeof(page3_7302), - NULL, 0); - if (0 <= ret) - ret = setbrightcont(gspca_dev); - if (0 <= ret) - ret = setcolors(gspca_dev); - if (0 <= ret) - ret = setwhitebalance(gspca_dev); - if (0 <= ret) - ret = setredbalance(gspca_dev); - if (0 <= ret) - ret = setbluebalance(gspca_dev); - if (0 <= ret) - ret = setgain(gspca_dev); - if (0 <= ret) - ret = setexposure(gspca_dev); - if (0 <= ret) - ret = sethvflip(gspca_dev); + reg_w_var(gspca_dev, start_7302, + page3_7302, sizeof(page3_7302)); + setbrightcont(gspca_dev); + setcolors(gspca_dev); + setwhitebalance(gspca_dev); + setredbalance(gspca_dev); + setbluebalance(gspca_dev); + setgain(gspca_dev); + setexposure(gspca_dev); + sethvflip(gspca_dev); /* only resolution 640x480 is supported for pac7302 */ @@ -771,34 +730,27 @@ static int sd_start(struct gspca_dev *gspca_dev) atomic_set(&sd->avg_lum, -1); /* start stream */ - if (0 <= ret) - ret = reg_w(gspca_dev, 0xff, 0x01); - if (0 <= ret) - ret = reg_w(gspca_dev, 0x78, 0x01); + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x01); - return ret; + return gspca_dev->usb_err; } static void sd_stopN(struct gspca_dev *gspca_dev) { - int ret; /* stop stream */ - ret = reg_w(gspca_dev, 0xff, 0x01); - if (0 <= ret) - ret = reg_w(gspca_dev, 0x78, 0x00); + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x00); } /* called on streamoff with alt 0 and on disconnect for pac7302 */ static void sd_stop0(struct gspca_dev *gspca_dev) { - int ret; - if (!gspca_dev->present) return; - ret = reg_w(gspca_dev, 0xff, 0x01); - if (0 <= ret) - ret = reg_w(gspca_dev, 0x78, 0x40); + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x40); } /* Include pac common sof detection functions */ @@ -808,22 +760,13 @@ static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int avg_lum = atomic_read(&sd->avg_lum); - int desired_lum, deadzone; + int desired_lum; + const int deadzone = 30; if (avg_lum == -1) return; - desired_lum = 270 + sd->brightness * 4; - /* Hack hack, with the 7202 the first exposure step is - pretty large, so if we're about to make the first - exposure increase make the deadzone large to avoid - oscilating */ - if (desired_lum > avg_lum && sd->gain == GAIN_DEF && - sd->exposure > EXPOSURE_DEF && - sd->exposure < 42) - deadzone = 90; - else - deadzone = 30; + desired_lum = 270 + sd->brightness; if (sd->autogain_ignore_frames > 0) sd->autogain_ignore_frames--; @@ -947,7 +890,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) sd->brightness = val; if (gspca_dev->streaming) setbrightcont(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) @@ -966,7 +909,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) if (gspca_dev->streaming) { setbrightcont(gspca_dev); } - return 0; + return gspca_dev->usb_err; } static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) @@ -984,7 +927,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) sd->colors = val; if (gspca_dev->streaming) setcolors(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) @@ -998,14 +941,11 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - int ret = 0; sd->white_balance = val; if (gspca_dev->streaming) - ret = setwhitebalance(gspca_dev); - if (0 <= ret) - ret = 0; - return ret; + setwhitebalance(gspca_dev); + return gspca_dev->usb_err; } static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) @@ -1019,14 +959,11 @@ static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - int ret = 0; sd->red_balance = val; if (gspca_dev->streaming) - ret = setredbalance(gspca_dev); - if (0 <= ret) - ret = 0; - return ret; + setredbalance(gspca_dev); + return gspca_dev->usb_err; } static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val) @@ -1040,14 +977,11 @@ static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val) static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - int ret = 0; sd->blue_balance = val; if (gspca_dev->streaming) - ret = setbluebalance(gspca_dev); - if (0 <= ret) - ret = 0; - return ret; + setbluebalance(gspca_dev); + return gspca_dev->usb_err; } static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val) @@ -1065,7 +999,7 @@ static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) sd->gain = val; if (gspca_dev->streaming) setgain(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) @@ -1083,7 +1017,7 @@ static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) sd->exposure = val; if (gspca_dev->streaming) setexposure(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) @@ -1114,7 +1048,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) } } - return 0; + return gspca_dev->usb_err; } static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) @@ -1132,7 +1066,7 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) sd->hflip = val; if (gspca_dev->streaming) sethvflip(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -1150,7 +1084,7 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) sd->vflip = val; if (gspca_dev->streaming) sethvflip(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -1165,7 +1099,6 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) static int sd_dbg_s_register(struct gspca_dev *gspca_dev, struct v4l2_dbg_register *reg) { - int ret = -EINVAL; __u8 index; __u8 value; @@ -1185,14 +1118,12 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev, /* Note that there shall be no access to other page by any other function between the page swith and the actual register write */ - ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - if (0 <= ret) - ret = reg_w(gspca_dev, index, value); + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, index, value); - if (0 <= ret) - ret = reg_w(gspca_dev, 0xdc, 0x01); + reg_w(gspca_dev, 0xdc, 0x01); } - return ret; + return gspca_dev->usb_err; } static int sd_chip_ident(struct gspca_dev *gspca_dev, @@ -1210,8 +1141,39 @@ static int sd_chip_ident(struct gspca_dev *gspca_dev, } #endif +#ifdef CONFIG_INPUT +static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* interrupt packet data */ + int len) /* interrput packet length */ +{ + int ret = -EINVAL; + u8 data0, data1; + + if (len == 2) { + data0 = data[0]; + data1 = data[1]; + if ((data0 == 0x00 && data1 == 0x11) || + (data0 == 0x22 && data1 == 0x33) || + (data0 == 0x44 && data1 == 0x55) || + (data0 == 0x66 && data1 == 0x77) || + (data0 == 0x88 && data1 == 0x99) || + (data0 == 0xaa && data1 == 0xbb) || + (data0 == 0xcc && data1 == 0xdd) || + (data0 == 0xee && data1 == 0xff)) { + 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; + } + } + + return ret; +} +#endif + /* sub-driver description for pac7302 */ -static struct sd_desc sd_desc = { +static const struct sd_desc sd_desc = { .name = MODULE_NAME, .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), @@ -1226,6 +1188,9 @@ static struct sd_desc sd_desc = { .set_register = sd_dbg_s_register, .get_chip_ident = sd_chip_ident, #endif +#ifdef CONFIG_INPUT + .int_pkt_scan = sd_int_pkt_scan, +#endif }; /* -- module initialisation -- */ |