diff options
| author | Alan Cox <alan@lxorguk.ukuu.org.uk> | 2002-10-27 22:44:46 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-10-27 22:44:46 -0800 |
| commit | 002b40d895976f542beebe1e3db27bdb8b28454e (patch) | |
| tree | 53da5004b103de1d5934654d9f66040a29b9120c | |
| parent | 4a142abaef4b0572772c864acd3b5fc32b6ad976 (diff) | |
[PATCH] cpia driver update from maintainer
| -rw-r--r-- | drivers/media/video/cpia.c | 1497 | ||||
| -rw-r--r-- | drivers/media/video/cpia.h | 57 | ||||
| -rw-r--r-- | drivers/media/video/cpia_pp.c | 9 | ||||
| -rw-r--r-- | drivers/media/video/cpia_usb.c | 7 |
4 files changed, 1179 insertions, 391 deletions
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index 24b9f56023fb..d57cd471d6b4 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -6,6 +6,7 @@ * (C) Copyright 1999-2000 Peter Pregler * (C) Copyright 1999-2000 Scott J. Bertin * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com> + * (C) Copyright 2000 STMicroelectronics * * 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 @@ -30,7 +31,6 @@ #include <linux/init.h> #include <linux/fs.h> #include <linux/vmalloc.h> -#include <linux/delay.h> #include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/ctype.h> @@ -101,6 +101,7 @@ MODULE_SUPPORTED_DEVICE("video"); #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13) #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1) +#define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2) #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3) #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4) #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6) @@ -131,6 +132,7 @@ MODULE_SUPPORTED_DEVICE("video"); #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12) #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13) #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14) +#define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15) #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1) #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4) @@ -139,6 +141,7 @@ MODULE_SUPPORTED_DEVICE("video"); #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8) #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9) #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10) +#define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11) enum { FRAME_READY, /* Ready to grab into */ @@ -164,6 +167,25 @@ enum { #define COMMAND_SETFLICKERCTRL 0x2000 #define COMMAND_SETVLOFFSET 0x4000 #define COMMAND_SETLIGHTS 0x8000 + +#define ROUND_UP_EXP_FOR_FLICKER 15 + +/* Constants for automatic frame rate adjustment */ +#define MAX_EXP 302 +#define MAX_EXP_102 255 +#define LOW_EXP 140 +#define VERY_LOW_EXP 70 +#define TC 94 +#define EXP_ACC_DARK 50 +#define EXP_ACC_LIGHT 90 +#define HIGH_COMP_102 160 +#define MAX_COMP 239 +#define DARK_TIME 3 +#define LIGHT_TIME 3 + +/* Maximum number of 10ms loops to wait for the stream to become ready */ +#define READY_TIMEOUT 100 + /* Developer's Guide Table 5 p 3-34 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/ static u8 flicker_jumps[2][2][4] = @@ -173,6 +195,10 @@ static u8 flicker_jumps[2][2][4] = /* forward declaration of local function */ static void reset_camera_struct(struct cam_data *cam); +static int find_over_exposure(int brightness); +static void set_flicker(struct cam_params *params, volatile u32 *command_flags, + int on); + /********************************************************************** * @@ -291,12 +317,6 @@ static int cpia_read_proc(char *page, char **start, off_t off, out += sprintf(out, "video_size: %s\n", cam->params.format.videoSize == VIDEOSIZE_CIF ? "CIF " : "QCIF"); - out += sprintf(out, "sub_sample: %s\n", - cam->params.format.subSample == SUBSAMPLE_420 ? - "420" : "422"); - out += sprintf(out, "yuv_order: %s\n", - cam->params.format.yuvOrder == YUVORDER_YUYV ? - "YUYV" : "UYVY"); out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n", cam->params.roi.colStart*8, cam->params.roi.rowStart*4, @@ -331,11 +351,17 @@ static int cpia_read_proc(char *page, char **start, off_t off, 2*cam->params.streamStartLine, 0, cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144, cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120); + out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n", + cam->params.format.subSample == SUBSAMPLE_420 ? + "420" : "422", "420", "422", "422"); + out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n", + cam->params.format.yuvOrder == YUVORDER_YUYV ? + "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV"); out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n", cam->params.ecpTiming ? "slow" : "normal", "slow", "normal", "normal"); - if (cam->params.colourBalance.balanceModeIsAuto) { + if (cam->params.colourBalance.balanceMode == 2) { sprintf(tmpstr, "auto"); } else { sprintf(tmpstr, "manual"); @@ -385,31 +411,33 @@ static int cpia_read_proc(char *page, char **start, off_t off, 1<<cam->params.exposure.gain, 1, 1); if (cam->params.version.firmwareVersion == 1 && cam->params.version.firmwareRevision == 2) - /* 1-02 firmware limits fineExp to 127 */ - tmp = 255; + /* 1-02 firmware limits fineExp/2 to 127 */ + tmp = 254; else - tmp = 511; + tmp = 510; out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n", cam->params.exposure.fineExp*2, 0, tmp, 0); if (cam->params.version.firmwareVersion == 1 && cam->params.version.firmwareRevision == 2) /* 1-02 firmware limits coarseExpHi to 0 */ - tmp = 255; + tmp = MAX_EXP_102; else - tmp = 65535; + tmp = MAX_EXP; out += sprintf(out, "coarse_exp: %8d %8d %8d" " %8d\n", cam->params.exposure.coarseExpLo+ 256*cam->params.exposure.coarseExpHi, 0, tmp, 185); out += sprintf(out, "red_comp: %8d %8d %8d %8d\n", - cam->params.exposure.redComp, 220, 255, 220); + cam->params.exposure.redComp, COMP_RED, 255, COMP_RED); out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n", - cam->params.exposure.green1Comp, 214, 255, 214); + cam->params.exposure.green1Comp, COMP_GREEN1, 255, + COMP_GREEN1); out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n", - cam->params.exposure.green2Comp, 214, 255, 214); + cam->params.exposure.green2Comp, COMP_GREEN2, 255, + COMP_GREEN2); out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n", - cam->params.exposure.blueComp, 230, 255, 230); + cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE); out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n", cam->params.apcor.gain1, 0, 0xff, 0x1c); @@ -433,9 +461,14 @@ static int cpia_read_proc(char *page, char **start, off_t off, out += sprintf(out, "mains_frequency: %8d %8d %8d %8d" " only 50/60\n", cam->mainsFreq ? 60 : 50, 50, 60, 50); - out += sprintf(out, "allowable_overexposure: %8d %8d %8d %8d\n", - cam->params.flickerControl.allowableOverExposure, 0, - 255, 0); + if(cam->params.flickerControl.allowableOverExposure < 0) + out += sprintf(out, "allowable_overexposure: %4dauto auto %8d auto\n", + -cam->params.flickerControl.allowableOverExposure, + 255); + else + out += sprintf(out, "allowable_overexposure: %8d auto %8d auto\n", + cam->params.flickerControl.allowableOverExposure, + 255); out += sprintf(out, "compression_mode: "); switch(cam->params.compression.mode) { case CPIA_COMPRESSION_NONE: @@ -453,8 +486,8 @@ static int cpia_read_proc(char *page, char **start, off_t off, } out += sprintf(out, " none,auto,manual auto\n"); out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n", - cam->params.compression.decimation == - DECIMATION_ENAB ? "on":"off", "off", "off", + cam->params.compression.decimation == + DECIMATION_ENAB ? "on":"off", "off", "on", "off"); out += sprintf(out, "compression_target: %9s %9s %9s %9s\n", cam->params.compressionTarget.frTargeting == @@ -462,13 +495,13 @@ static int cpia_read_proc(char *page, char **start, off_t off, "framerate":"quality", "framerate", "quality", "quality"); out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n", - cam->params.compressionTarget.targetFR, 0, 30, 7); + cam->params.compressionTarget.targetFR, 1, 30, 15); out += sprintf(out, "target_quality: %8d %8d %8d %8d\n", - cam->params.compressionTarget.targetQ, 0, 255, 10); + cam->params.compressionTarget.targetQ, 1, 64, 5); out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n", - cam->params.yuvThreshold.yThreshold, 0, 31, 15); + cam->params.yuvThreshold.yThreshold, 0, 31, 6); out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n", - cam->params.yuvThreshold.uvThreshold, 0, 31, 15); + cam->params.yuvThreshold.uvThreshold, 0, 31, 6); out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n", cam->params.compressionParams.hysteresis, 0, 255, 3); out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n", @@ -511,6 +544,47 @@ static int cpia_read_proc(char *page, char **start, off_t off, return len; } + +static int match(char *checkstr, char **buffer, unsigned long *count, + int *find_colon, int *err) +{ + int ret, colon_found = 1; + int len = strlen(checkstr); + ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0); + if (ret) { + *buffer += len; + *count -= len; + if (*find_colon) { + colon_found = 0; + while (*count && (**buffer == ' ' || **buffer == '\t' || + (!colon_found && **buffer == ':'))) { + if (**buffer == ':') + colon_found = 1; + --*count; + ++*buffer; + } + if (!*count || !colon_found) + *err = -EINVAL; + *find_colon = 0; + } + } + return ret; +} + +static unsigned long int value(char **buffer, unsigned long *count, int *err) +{ + char *p; + unsigned long int ret; + ret = simple_strtoul(*buffer, &p, 0); + if (p == *buffer) + *err = -EINVAL; + else { + *count -= p - *buffer; + *buffer = p; + } + return ret; +} + static int cpia_write_proc(struct file *file, const char *buf, unsigned long count, void *data) { @@ -565,45 +639,11 @@ static int cpia_write_proc(struct file *file, const char *buf, memcpy(&new_params, &cam->params, sizeof(struct cam_params)); new_mains = cam->mainsFreq; -#define MATCH(x) \ - ({ \ - int _len = strlen(x), _ret, _colon_found; \ - _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \ - if (_ret) { \ - buffer += _len; \ - count -= _len; \ - if (find_colon) { \ - _colon_found = 0; \ - while (count && (*buffer == ' ' || *buffer == '\t' || \ - (!_colon_found && *buffer == ':'))) { \ - if (*buffer == ':') \ - _colon_found = 1; \ - --count; \ - ++buffer; \ - } \ - if (!count || !_colon_found) \ - retval = -EINVAL; \ - find_colon = 0; \ - } \ - } \ - _ret; \ - }) +#define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval)) +#define VALUE (value(&buffer,&count, &retval)) #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \ new_params.version.firmwareRevision == (y)) -#define VALUE \ - ({ \ - char *_p; \ - unsigned long int _ret; \ - _ret = simple_strtoul(buffer, &_p, 0); \ - if (_p == buffer) \ - retval = -EINVAL; \ - else { \ - count -= _p - buffer; \ - buffer = _p; \ - } \ - _ret; \ - }) - + retval = 0; while (count && !retval) { find_colon = 1; @@ -618,6 +658,12 @@ static int cpia_write_proc(struct file *file, const char *buf, retval = -EINVAL; } command_flags |= COMMAND_SETCOLOURPARAMS; + if(new_params.flickerControl.allowableOverExposure < 0) + new_params.flickerControl.allowableOverExposure = + -find_over_exposure(new_params.colourParams.brightness); + if(new_params.flickerControl.flickerMode != 0) + command_flags |= COMMAND_SETFLICKERCTRL; + } else if (MATCH("contrast")) { if (!retval) val = VALUE; @@ -686,6 +732,7 @@ static int cpia_write_proc(struct file *file, const char *buf, command_flags |= COMMAND_SETFLICKERCTRL; } command_flags |= COMMAND_SETSENSORFPS; + cam->exposure_status = EXPOSURE_NORMAL; } else if (MATCH("stream_start_line")) { if (!retval) val = VALUE; @@ -700,6 +747,24 @@ static int cpia_write_proc(struct file *file, const char *buf, else retval = -EINVAL; } + } else if (MATCH("sub_sample")) { + if (!retval && MATCH("420")) + new_params.format.subSample = SUBSAMPLE_420; + else if (!retval && MATCH("422")) + new_params.format.subSample = SUBSAMPLE_422; + else + retval = -EINVAL; + + command_flags |= COMMAND_SETFORMAT; + } else if (MATCH("yuv_order")) { + if (!retval && MATCH("YUYV")) + new_params.format.yuvOrder = YUVORDER_YUYV; + else if (!retval && MATCH("UYVY")) + new_params.format.yuvOrder = YUVORDER_UYVY; + else + retval = -EINVAL; + + command_flags |= COMMAND_SETFORMAT; } else if (MATCH("ecp_timing")) { if (!retval && MATCH("normal")) new_params.ecpTiming = 0; @@ -711,9 +776,9 @@ static int cpia_write_proc(struct file *file, const char *buf, command_flags |= COMMAND_SETECPTIMING; } else if (MATCH("color_balance_mode")) { if (!retval && MATCH("manual")) - new_params.colourBalance.balanceModeIsAuto = 0; + new_params.colourBalance.balanceMode = 3; else if (!retval && MATCH("auto")) - new_params.colourBalance.balanceModeIsAuto = 1; + new_params.colourBalance.balanceMode = 2; else retval = -EINVAL; @@ -723,9 +788,10 @@ static int cpia_write_proc(struct file *file, const char *buf, val = VALUE; if (!retval) { - if (val <= 212) + if (val <= 212) { new_params.colourBalance.redGain = val; - else + new_params.colourBalance.balanceMode = 1; + } else retval = -EINVAL; } command_flags |= COMMAND_SETCOLOURBALANCE; @@ -734,9 +800,10 @@ static int cpia_write_proc(struct file *file, const char *buf, val = VALUE; if (!retval) { - if (val <= 212) + if (val <= 212) { new_params.colourBalance.greenGain = val; - else + new_params.colourBalance.balanceMode = 1; + } else retval = -EINVAL; } command_flags |= COMMAND_SETCOLOURBALANCE; @@ -745,9 +812,10 @@ static int cpia_write_proc(struct file *file, const char *buf, val = VALUE; if (!retval) { - if (val <= 212) + if (val <= 212) { new_params.colourBalance.blueGain = val; - else + new_params.colourBalance.balanceMode = 1; + } else retval = -EINVAL; } command_flags |= COMMAND_SETCOLOURBALANCE; @@ -784,8 +852,9 @@ static int cpia_write_proc(struct file *file, const char *buf, else if (!retval && MATCH("manual")) { if (new_params.exposure.expMode == 2) new_params.exposure.expMode = 3; + if(new_params.flickerControl.flickerMode != 0) + command_flags |= COMMAND_SETFLICKERCTRL; new_params.flickerControl.flickerMode = 0; - command_flags |= COMMAND_SETFLICKERCTRL; } else retval = -EINVAL; @@ -807,32 +876,24 @@ static int cpia_write_proc(struct file *file, const char *buf, switch(val) { case 1: new_params.exposure.gain = 0; - new_params.exposure.expMode = 1; - new_params.flickerControl.flickerMode = 0; - command_flags |= COMMAND_SETFLICKERCTRL; break; case 2: new_params.exposure.gain = 1; - new_params.exposure.expMode = 1; - new_params.flickerControl.flickerMode = 0; - command_flags |= COMMAND_SETFLICKERCTRL; break; case 4: new_params.exposure.gain = 2; - new_params.exposure.expMode = 1; - new_params.flickerControl.flickerMode = 0; - command_flags |= COMMAND_SETFLICKERCTRL; break; case 8: new_params.exposure.gain = 3; - new_params.exposure.expMode = 1; - new_params.flickerControl.flickerMode = 0; - command_flags |= COMMAND_SETFLICKERCTRL; break; default: retval = -EINVAL; break; } + new_params.exposure.expMode = 1; + if(new_params.flickerControl.flickerMode != 0) + command_flags |= COMMAND_SETFLICKERCTRL; + new_params.flickerControl.flickerMode = 0; command_flags |= COMMAND_SETEXPOSURE; if (new_params.exposure.gain > new_params.exposure.gainMode-1) @@ -840,16 +901,18 @@ static int cpia_write_proc(struct file *file, const char *buf, } } else if (MATCH("fine_exp")) { if (!retval) - val = VALUE; + val = VALUE/2; if (!retval) { if (val < 256) { - /* 1-02 firmware limits fineExp to 127*/ + /* 1-02 firmware limits fineExp/2 to 127*/ if (FIRMWARE_VERSION(1,2) && val > 127) val = 127; new_params.exposure.fineExp = val; new_params.exposure.expMode = 1; command_flags |= COMMAND_SETEXPOSURE; + if(new_params.flickerControl.flickerMode != 0) + command_flags |= COMMAND_SETFLICKERCTRL; new_params.flickerControl.flickerMode = 0; command_flags |= COMMAND_SETFLICKERCTRL; } else @@ -860,17 +923,18 @@ static int cpia_write_proc(struct file *file, const char *buf, val = VALUE; if (!retval) { - if (val < 65536) { - /* 1-02 firmware limits - * coarseExp to 255 */ - if (FIRMWARE_VERSION(1,2) && val > 255) - val = 255; + if (val <= MAX_EXP) { + if (FIRMWARE_VERSION(1,2) && + val > MAX_EXP_102) + val = MAX_EXP_102; new_params.exposure.coarseExpLo = val & 0xff; new_params.exposure.coarseExpHi = val >> 8; new_params.exposure.expMode = 1; command_flags |= COMMAND_SETEXPOSURE; + if(new_params.flickerControl.flickerMode != 0) + command_flags |= COMMAND_SETFLICKERCTRL; new_params.flickerControl.flickerMode = 0; command_flags |= COMMAND_SETFLICKERCTRL; } else @@ -881,8 +945,9 @@ static int cpia_write_proc(struct file *file, const char *buf, val = VALUE; if (!retval) { - if (val >= 220 && val <= 255) { + if (val >= COMP_RED && val <= 255) { new_params.exposure.redComp = val; + new_params.exposure.compMode = 1; command_flags |= COMMAND_SETEXPOSURE; } else retval = -EINVAL; @@ -892,8 +957,9 @@ static int cpia_write_proc(struct file *file, const char *buf, val = VALUE; if (!retval) { - if (val >= 214 && val <= 255) { + if (val >= COMP_GREEN1 && val <= 255) { new_params.exposure.green1Comp = val; + new_params.exposure.compMode = 1; command_flags |= COMMAND_SETEXPOSURE; } else retval = -EINVAL; @@ -903,8 +969,9 @@ static int cpia_write_proc(struct file *file, const char *buf, val = VALUE; if (!retval) { - if (val >= 214 && val <= 255) { + if (val >= COMP_GREEN2 && val <= 255) { new_params.exposure.green2Comp = val; + new_params.exposure.compMode = 1; command_flags |= COMMAND_SETEXPOSURE; } else retval = -EINVAL; @@ -914,8 +981,9 @@ static int cpia_write_proc(struct file *file, const char *buf, val = VALUE; if (!retval) { - if (val >= 230 && val <= 255) { + if (val >= COMP_BLUE && val <= 255) { new_params.exposure.blueComp = val; + new_params.exposure.compMode = 1; command_flags |= COMMAND_SETEXPOSURE; } else retval = -EINVAL; @@ -1010,12 +1078,10 @@ static int cpia_write_proc(struct file *file, const char *buf, command_flags |= COMMAND_SETVLOFFSET; } else if (MATCH("flicker_control")) { if (!retval && MATCH("on")) { - new_params.flickerControl.flickerMode = 1; - new_params.exposure.expMode = 2; - command_flags |= COMMAND_SETEXPOSURE; - } else if (!retval && MATCH("off")) - new_params.flickerControl.flickerMode = 0; - else + set_flicker(&new_params, &command_flags, 1); + } else if (!retval && MATCH("off")) { + set_flicker(&new_params, &command_flags, 0); + } else retval = -EINVAL; command_flags |= COMMAND_SETFLICKERCTRL; @@ -1039,16 +1105,24 @@ static int cpia_write_proc(struct file *file, const char *buf, } else retval = -EINVAL; } else if (MATCH("allowable_overexposure")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) { - new_params.flickerControl. - allowableOverExposure = val; + if (!retval && MATCH("auto")) { + new_params.flickerControl.allowableOverExposure = + -find_over_exposure(new_params.colourParams.brightness); + if(new_params.flickerControl.flickerMode != 0) command_flags |= COMMAND_SETFLICKERCTRL; - } else - retval = -EINVAL; + } else { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) { + new_params.flickerControl. + allowableOverExposure = val; + if(new_params.flickerControl.flickerMode != 0) + command_flags |= COMMAND_SETFLICKERCTRL; + } else + retval = -EINVAL; + } } } else if (MATCH("compression_mode")) { if (!retval && MATCH("none")) @@ -1067,6 +1141,8 @@ static int cpia_write_proc(struct file *file, const char *buf, } else if (MATCH("decimation_enable")) { if (!retval && MATCH("off")) new_params.compression.decimation = 0; + else if (!retval && MATCH("on")) + new_params.compression.decimation = 1; else retval = -EINVAL; @@ -1086,16 +1162,23 @@ static int cpia_write_proc(struct file *file, const char *buf, if (!retval) val = VALUE; - if (!retval) - new_params.compressionTarget.targetFR = val; + if (!retval) { + if(val > 0 && val <= 30) + new_params.compressionTarget.targetFR = val; + else + retval = -EINVAL; + } command_flags |= COMMAND_SETCOMPRESSIONTARGET; } else if (MATCH("target_quality")) { if (!retval) val = VALUE; - if (!retval) - new_params.compressionTarget.targetQ = val; - + if (!retval) { + if(val > 0 && val <= 64) + new_params.compressionTarget.targetQ = val; + else + retval = -EINVAL; + } command_flags |= COMMAND_SETCOMPRESSIONTARGET; } else if (MATCH("y_threshold")) { if (!retval) @@ -1247,10 +1330,8 @@ static int cpia_write_proc(struct file *file, const char *buf, } } #undef MATCH -#undef FIRMWARE_VERSION #undef VALUE -#undef FIND_VALUE -#undef FIND_END +#undef FIRMWARE_VERSION if (!retval) { if (command_flags & COMMAND_SETCOLOURPARAMS) { /* Adjust cam->vp to reflect these changes */ @@ -1261,7 +1342,10 @@ static int cpia_write_proc(struct file *file, const char *buf, cam->vp.colour = new_params.colourParams.saturation*65535/100; } - + if((command_flags & COMMAND_SETEXPOSURE) && + new_params.exposure.expMode == 2) + cam->exposure_status = EXPOSURE_NORMAL; + memcpy(&cam->params, &new_params, sizeof(struct cam_params)); cam->mainsFreq = new_mains; cam->cmd_queue |= command_flags; @@ -1294,11 +1378,11 @@ static void create_proc_cpia_cam(struct cam_data *cam) ent->read_proc = cpia_read_proc; ent->write_proc = cpia_write_proc; /* - size of the proc entry is 3672 bytes for the standard webcam; - the extra features of the QX3 microscope add 188 bytes. + size of the proc entry is 3736 bytes for the standard webcam; + the extra features of the QX3 microscope add 189 bytes. (we have not yet probed the camera to see which type it is). */ - ent->size = 3672 + 188; + ent->size = 3736 + 189; cam->proc_entry = ent; } @@ -1324,10 +1408,12 @@ static void proc_cpia_create(void) LOG("Unable to initialise /proc/cpia\n"); } +#ifdef MODULE static void proc_cpia_destroy(void) { remove_proc_entry("cpia", 0); } +#endif /*MODULE*/ #endif /* CONFIG_PROC_FS */ /* ----------------------- debug functions ---------------------- */ @@ -1410,9 +1496,7 @@ static void set_vw_size(struct cam_data *cam) cam->vw.height = 288; cam->params.format.videoSize=VIDEOSIZE_CIF; cam->params.roi.colStart=0; - cam->params.roi.colEnd=44; cam->params.roi.rowStart=0; - cam->params.roi.rowEnd=72; cam->params.streamStartLine = 120; break; case VIDEOSIZE_SIF: @@ -1420,9 +1504,7 @@ static void set_vw_size(struct cam_data *cam) cam->vw.height = 240; cam->params.format.videoSize=VIDEOSIZE_CIF; cam->params.roi.colStart=2; - cam->params.roi.colEnd=42; cam->params.roi.rowStart=6; - cam->params.roi.rowEnd=66; cam->params.streamStartLine = 120; break; case VIDEOSIZE_288_216: @@ -1430,9 +1512,7 @@ static void set_vw_size(struct cam_data *cam) cam->vw.height = 216; cam->params.format.videoSize=VIDEOSIZE_CIF; cam->params.roi.colStart=4; - cam->params.roi.colEnd=40; cam->params.roi.rowStart=9; - cam->params.roi.rowEnd=63; cam->params.streamStartLine = 120; break; case VIDEOSIZE_256_192: @@ -1440,9 +1520,7 @@ static void set_vw_size(struct cam_data *cam) cam->vw.height = 192; cam->params.format.videoSize=VIDEOSIZE_CIF; cam->params.roi.colStart=6; - cam->params.roi.colEnd=38; cam->params.roi.rowStart=12; - cam->params.roi.rowEnd=60; cam->params.streamStartLine = 120; break; case VIDEOSIZE_224_168: @@ -1450,9 +1528,7 @@ static void set_vw_size(struct cam_data *cam) cam->vw.height = 168; cam->params.format.videoSize=VIDEOSIZE_CIF; cam->params.roi.colStart=8; - cam->params.roi.colEnd=36; cam->params.roi.rowStart=15; - cam->params.roi.rowEnd=57; cam->params.streamStartLine = 120; break; case VIDEOSIZE_192_144: @@ -1460,9 +1536,7 @@ static void set_vw_size(struct cam_data *cam) cam->vw.height = 144; cam->params.format.videoSize=VIDEOSIZE_CIF; cam->params.roi.colStart=10; - cam->params.roi.colEnd=34; cam->params.roi.rowStart=18; - cam->params.roi.rowEnd=54; cam->params.streamStartLine = 120; break; case VIDEOSIZE_QCIF: @@ -1470,9 +1544,7 @@ static void set_vw_size(struct cam_data *cam) cam->vw.height = 144; cam->params.format.videoSize=VIDEOSIZE_QCIF; cam->params.roi.colStart=0; - cam->params.roi.colEnd=22; cam->params.roi.rowStart=0; - cam->params.roi.rowEnd=36; cam->params.streamStartLine = 60; break; case VIDEOSIZE_QSIF: @@ -1480,9 +1552,7 @@ static void set_vw_size(struct cam_data *cam) cam->vw.height = 120; cam->params.format.videoSize=VIDEOSIZE_QCIF; cam->params.roi.colStart=1; - cam->params.roi.colEnd=21; cam->params.roi.rowStart=3; - cam->params.roi.rowEnd=33; cam->params.streamStartLine = 60; break; case VIDEOSIZE_128_96: @@ -1490,9 +1560,7 @@ static void set_vw_size(struct cam_data *cam) cam->vw.height = 96; cam->params.format.videoSize=VIDEOSIZE_QCIF; cam->params.roi.colStart=3; - cam->params.roi.colEnd=19; cam->params.roi.rowStart=6; - cam->params.roi.rowEnd=30; cam->params.streamStartLine = 60; break; case VIDEOSIZE_88_72: @@ -1500,9 +1568,7 @@ static void set_vw_size(struct cam_data *cam) cam->vw.height = 72; cam->params.format.videoSize=VIDEOSIZE_QCIF; cam->params.roi.colStart=5; - cam->params.roi.colEnd=16; cam->params.roi.rowStart=9; - cam->params.roi.rowEnd=27; cam->params.streamStartLine = 60; break; case VIDEOSIZE_64_48: @@ -1510,9 +1576,7 @@ static void set_vw_size(struct cam_data *cam) cam->vw.height = 48; cam->params.format.videoSize=VIDEOSIZE_QCIF; cam->params.roi.colStart=7; - cam->params.roi.colEnd=15; cam->params.roi.rowStart=12; - cam->params.roi.rowEnd=24; cam->params.streamStartLine = 60; break; case VIDEOSIZE_48_48: @@ -1520,15 +1584,26 @@ static void set_vw_size(struct cam_data *cam) cam->vw.height = 48; cam->params.format.videoSize=VIDEOSIZE_QCIF; cam->params.roi.colStart=8; - cam->params.roi.colEnd=14; cam->params.roi.rowStart=6; - cam->params.roi.rowEnd=30; cam->params.streamStartLine = 60; break; default: LOG("bad videosize value: %d\n", cam->video_size); + return; } + if(cam->vc.width == 0) + cam->vc.width = cam->vw.width; + if(cam->vc.height == 0) + cam->vc.height = cam->vw.height; + + cam->params.roi.colStart += cam->vc.x >> 3; + cam->params.roi.colEnd = cam->params.roi.colStart + + (cam->vc.width >> 3); + cam->params.roi.rowStart += cam->vc.y >> 2; + cam->params.roi.rowEnd = cam->params.roi.rowStart + + (cam->vc.height >> 2); + return; } @@ -1668,29 +1743,6 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d) cam->params.exposure.green1Comp = data[5]; cam->params.exposure.green2Comp = data[6]; cam->params.exposure.blueComp = data[7]; - /* If the *Comp parameters are wacko, generate - * a warning, and reset them back to default - * values. - rich@annexia.org - */ - if (cam->params.exposure.redComp < 220 || - cam->params.exposure.redComp > 255 || - cam->params.exposure.green1Comp < 214 || - cam->params.exposure.green1Comp > 255 || - cam->params.exposure.green2Comp < 214 || - cam->params.exposure.green2Comp > 255 || - cam->params.exposure.blueComp < 230 || - cam->params.exposure.blueComp > 255) - { - printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n", - cam->params.exposure.redComp, - cam->params.exposure.green1Comp, - cam->params.exposure.green2Comp, - cam->params.exposure.blueComp); - cam->params.exposure.redComp = 220; - cam->params.exposure.green1Comp = 214; - cam->params.exposure.green2Comp = 214; - cam->params.exposure.blueComp = 230; - } up(&cam->param_lock); break; @@ -1756,6 +1808,122 @@ static int do_command_extended(struct cam_data *cam, u16 command, **********************************************************************/ #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16) +static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt, + int linesize, int mmap_kludge) +{ + int y, u, v, r, g, b, y1; + + /* Odd lines use the same u and v as the previous line. + * Because of compression, it is necessary to get this + * information from the decoded image. */ + switch(out_fmt) { + case VIDEO_PALETTE_RGB555: + y = (*yuv++ - 16) * 76310; + y1 = (*yuv - 16) * 76310; + r = ((*(rgb+1-linesize)) & 0x7c) << 1; + g = ((*(rgb-linesize)) & 0xe0) >> 4 | + ((*(rgb+1-linesize)) & 0x03) << 6; + b = ((*(rgb-linesize)) & 0x1f) << 3; + u = (-53294 * r - 104635 * g + 157929 * b) / 5756495; + v = (157968 * r - 132278 * g - 25690 * b) / 5366159; + r = 104635 * v; + g = -25690 * u - 53294 * v; + b = 132278 * u; + *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3); + *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6); + *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3); + *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6); + return 4; + case VIDEO_PALETTE_RGB565: + y = (*yuv++ - 16) * 76310; + y1 = (*yuv - 16) * 76310; + r = (*(rgb+1-linesize)) & 0xf8; + g = ((*(rgb-linesize)) & 0xe0) >> 3 | + ((*(rgb+1-linesize)) & 0x07) << 5; + b = ((*(rgb-linesize)) & 0x1f) << 3; + u = (-53294 * r - 104635 * g + 157929 * b) / 5756495; + v = (157968 * r - 132278 * g - 25690 * b) / 5366159; + r = 104635 * v; + g = -25690 * u - 53294 * v; + b = 132278 * u; + *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3); + *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5); + *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3); + *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5); + return 4; + break; + case VIDEO_PALETTE_RGB24: + case VIDEO_PALETTE_RGB32: + y = (*yuv++ - 16) * 76310; + y1 = (*yuv - 16) * 76310; + if (mmap_kludge) { + r = *(rgb+2-linesize); + g = *(rgb+1-linesize); + b = *(rgb-linesize); + } else { + r = *(rgb-linesize); + g = *(rgb+1-linesize); + b = *(rgb+2-linesize); + } + u = (-53294 * r - 104635 * g + 157929 * b) / 5756495; + v = (157968 * r - 132278 * g - 25690 * b) / 5366159; + r = 104635 * v; + g = -25690 * u + -53294 * v; + b = 132278 * u; + if (mmap_kludge) { + *rgb++ = LIMIT(b+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(r+y); + if(out_fmt == VIDEO_PALETTE_RGB32) + rgb++; + *rgb++ = LIMIT(b+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(r+y1); + } else { + *rgb++ = LIMIT(r+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(b+y); + if(out_fmt == VIDEO_PALETTE_RGB32) + rgb++; + *rgb++ = LIMIT(r+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(b+y1); + } + if(out_fmt == VIDEO_PALETTE_RGB32) + return 8; + return 6; + case VIDEO_PALETTE_YUV422: + case VIDEO_PALETTE_YUYV: + y = *yuv++; + u = *(rgb+1-linesize); + y1 = *yuv; + v = *(rgb+3-linesize); + *rgb++ = y; + *rgb++ = u; + *rgb++ = y1; + *rgb = v; + return 4; + case VIDEO_PALETTE_UYVY: + u = *(rgb-linesize); + y = *yuv++; + v = *(rgb+2-linesize); + y1 = *yuv; + *rgb++ = u; + *rgb++ = y; + *rgb++ = v; + *rgb = y1; + return 4; + case VIDEO_PALETTE_GREY: + *rgb++ = *yuv++; + *rgb = *yuv; + return 2; + default: + DBG("Empty: %d\n", out_fmt); + return 0; + } +} + + static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt, int in_uyvy, int mmap_kludge) { @@ -1887,7 +2055,8 @@ static int skipcount(int count, int fmt) static int parse_picture(struct cam_data *cam, int size) { u8 *obuf, *ibuf, *end_obuf; - int ll, in_uyvy, compressed, origsize, out_fmt; + int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt; + int rows, cols, linesize, subsample_422; /* make sure params don't change while we are decoding */ down(&cam->param_lock); @@ -1910,11 +2079,12 @@ static int parse_picture(struct cam_data *cam, int size) return -1; } - if (ibuf[17] != SUBSAMPLE_422) { + if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) { LOG("illegal subtype %d\n",ibuf[17]); up(&cam->param_lock); return -1; } + subsample_422 = ibuf[17] == SUBSAMPLE_422; if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) { LOG("illegal yuvorder %d\n",ibuf[18]); @@ -1923,8 +2093,6 @@ static int parse_picture(struct cam_data *cam, int size) } in_uyvy = ibuf[18] == YUVORDER_UYVY; -#if 0 - /* FIXME: ROI mismatch occurs when switching capture sizes */ if ((ibuf[24] != cam->params.roi.colStart) || (ibuf[25] != cam->params.roi.colEnd) || (ibuf[26] != cam->params.roi.rowStart) || @@ -1933,7 +2101,9 @@ static int parse_picture(struct cam_data *cam, int size) up(&cam->param_lock); return -1; } -#endif + cols = 8*(ibuf[25] - ibuf[24]); + rows = 4*(ibuf[27] - ibuf[26]); + if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) { LOG("illegal compression %d\n",ibuf[28]); @@ -1942,12 +2112,13 @@ static int parse_picture(struct cam_data *cam, int size) } compressed = (ibuf[28] == COMPRESSED); - if (ibuf[29] != NO_DECIMATION) { - LOG("decimation not supported\n"); + if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) { + LOG("illegal decimation %d\n",ibuf[29]); up(&cam->param_lock); return -1; } - + decimation = (ibuf[29] == DECIMATION_ENAB); + cam->params.yuvThreshold.yThreshold = ibuf[30]; cam->params.yuvThreshold.uvThreshold = ibuf[31]; cam->params.status.systemState = ibuf[32]; @@ -1961,10 +2132,12 @@ static int parse_picture(struct cam_data *cam, int size) cam->fps = ibuf[41]; up(&cam->param_lock); + linesize = skipcount(cols, out_fmt); ibuf += FRAME_HEADER_SIZE; size -= FRAME_HEADER_SIZE; ll = ibuf[0] | (ibuf[1] << 8); ibuf += 2; + even_line = 1; while (size > 0) { size -= (ll+2); @@ -1975,16 +2148,24 @@ static int parse_picture(struct cam_data *cam, int size) while (ll > 1) { if (!compressed || (compressed && !(*ibuf & 1))) { + if(subsample_422 || even_line) { obuf += yuvconvert(ibuf, obuf, out_fmt, in_uyvy, cam->mmap_kludge); ibuf += 4; ll -= 4; } else { + /* SUBSAMPLE_420 on an odd line */ + obuf += convert420(ibuf, obuf, + out_fmt, linesize, + cam->mmap_kludge); + ibuf += 2; + ll -= 2; + } + } else { /*skip compressed interval from previous frame*/ - int skipsize = skipcount(*ibuf >> 1, out_fmt); - obuf += skipsize; + obuf += skipcount(*ibuf >> 1, out_fmt); if (obuf > end_obuf) { - LOG("Insufficient data in buffer\n"); + LOG("Insufficient buffer size\n"); return -1; } ++ibuf; @@ -1998,7 +2179,7 @@ static int parse_picture(struct cam_data *cam, int size) return -1; } - ibuf++; /* skip over EOL */ + ++ibuf; /* skip over EOL */ if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) && (ibuf[2] == EOI) && (ibuf[3] == EOI)) { @@ -2006,10 +2187,17 @@ static int parse_picture(struct cam_data *cam, int size) break; } + if(decimation) { + /* skip the odd lines for now */ + obuf += linesize; + } + if (size > 1) { ll = ibuf[0] | (ibuf[1] << 8); ibuf += 2; /* skip over line length */ } + if(!decimation) + even_line = !even_line; } else { LOG("line length was not 1 but %d after %d/%d bytes\n", ll, origsize-size, origsize); @@ -2017,6 +2205,25 @@ static int parse_picture(struct cam_data *cam, int size) } } + if(decimation) { + /* interpolate odd rows */ + int i, j; + u8 *prev, *next; + prev = cam->decompressed_frame.data; + obuf = prev+linesize; + next = obuf+linesize; + for(i=1; i<rows-1; i+=2) { + for(j=0; j<linesize; ++j) { + *obuf++ = ((int)*prev++ + *next++) / 2; + } + prev += linesize; + obuf += linesize; + next += linesize; + } + /* last row is odd, just copy previous row */ + memcpy(obuf, prev, linesize); + } + cam->decompressed_frame.count = obuf-cam->decompressed_frame.data; return cam->decompressed_frame.count; @@ -2029,6 +2236,38 @@ static inline int init_stream_cap(struct cam_data *cam) 0, cam->params.streamStartLine, 0, 0); } + +/* find_over_exposure + * Finds a suitable value of OverExposure for use with SetFlickerCtrl + * Some calculation is required because this value changes with the brightness + * set with SetColourParameters + * + * Parameters: Brightness - last brightness value set with SetColourParameters + * + * Returns: OverExposure value to use with SetFlickerCtrl + */ +#define FLICKER_MAX_EXPOSURE 250 +#define FLICKER_ALLOWABLE_OVER_EXPOSURE 146 +#define FLICKER_BRIGHTNESS_CONSTANT 59 +static int find_over_exposure(int brightness) +{ + int MaxAllowableOverExposure, OverExposure; + + MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness - + FLICKER_BRIGHTNESS_CONSTANT; + + if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) { + OverExposure = MaxAllowableOverExposure; + } else { + OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE; + } + + return OverExposure; +} +#undef FLICKER_MAX_EXPOSURE +#undef FLICKER_ALLOWABLE_OVER_EXPOSURE +#undef FLICKER_BRIGHTNESS_CONSTANT + /* update various camera modes and settings */ static void dispatch_commands(struct cam_data *cam) { @@ -2039,17 +2278,6 @@ static void dispatch_commands(struct cam_data *cam) } DEB_BYTE(cam->cmd_queue); DEB_BYTE(cam->cmd_queue>>8); - if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS) - do_command(cam, CPIA_COMMAND_SetColourParams, - cam->params.colourParams.brightness, - cam->params.colourParams.contrast, - cam->params.colourParams.saturation, 0); - - if (cam->cmd_queue & COMMAND_SETCOMPRESSION) - do_command(cam, CPIA_COMMAND_SetCompression, - cam->params.compression.mode, - cam->params.compression.decimation, 0, 0); - if (cam->cmd_queue & COMMAND_SETFORMAT) { do_command(cam, CPIA_COMMAND_SetFormat, cam->params.format.videoSize, @@ -2061,37 +2289,30 @@ static void dispatch_commands(struct cam_data *cam) cam->first_frame = 1; } - if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET) - do_command(cam, CPIA_COMMAND_SetCompressionTarget, - cam->params.compressionTarget.frTargeting, - cam->params.compressionTarget.targetFR, - cam->params.compressionTarget.targetQ, 0); - - if (cam->cmd_queue & COMMAND_SETYUVTHRESH) - do_command(cam, CPIA_COMMAND_SetYUVThresh, - cam->params.yuvThreshold.yThreshold, - cam->params.yuvThreshold.uvThreshold, 0, 0); + if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS) + do_command(cam, CPIA_COMMAND_SetColourParams, + cam->params.colourParams.brightness, + cam->params.colourParams.contrast, + cam->params.colourParams.saturation, 0); - if (cam->cmd_queue & COMMAND_SETECPTIMING) - do_command(cam, CPIA_COMMAND_SetECPTiming, - cam->params.ecpTiming, 0, 0, 0); + if (cam->cmd_queue & COMMAND_SETAPCOR) + do_command(cam, CPIA_COMMAND_SetApcor, + cam->params.apcor.gain1, + cam->params.apcor.gain2, + cam->params.apcor.gain4, + cam->params.apcor.gain8); - if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS) - do_command_extended(cam, CPIA_COMMAND_SetCompressionParams, - 0, 0, 0, 0, - cam->params.compressionParams.hysteresis, - cam->params.compressionParams.threshMax, - cam->params.compressionParams.smallStep, - cam->params.compressionParams.largeStep, - cam->params.compressionParams.decimationHysteresis, - cam->params.compressionParams.frDiffStepThresh, - cam->params.compressionParams.qDiffStepThresh, - cam->params.compressionParams.decimationThreshMod); + if (cam->cmd_queue & COMMAND_SETVLOFFSET) + do_command(cam, CPIA_COMMAND_SetVLOffset, + cam->params.vlOffset.gain1, + cam->params.vlOffset.gain2, + cam->params.vlOffset.gain4, + cam->params.vlOffset.gain8); - if (cam->cmd_queue & COMMAND_SETEXPOSURE) + if (cam->cmd_queue & COMMAND_SETEXPOSURE) { do_command_extended(cam, CPIA_COMMAND_SetExposure, cam->params.exposure.gainMode, - cam->params.exposure.expMode, + 1, cam->params.exposure.compMode, cam->params.exposure.centreWeight, cam->params.exposure.gain, @@ -2102,12 +2323,21 @@ static void dispatch_commands(struct cam_data *cam) cam->params.exposure.green1Comp, cam->params.exposure.green2Comp, cam->params.exposure.blueComp); - + if(cam->params.exposure.expMode != 1) { + do_command_extended(cam, CPIA_COMMAND_SetExposure, + 0, + cam->params.exposure.expMode, + 0, 0, + cam->params.exposure.gain, + cam->params.exposure.fineExp, + cam->params.exposure.coarseExpLo, + cam->params.exposure.coarseExpHi, + 0, 0, 0, 0); + } + } + if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) { - if (cam->params.colourBalance.balanceModeIsAuto) { - do_command(cam, CPIA_COMMAND_SetColourBalance, - 2, 0, 0, 0); - } else { + if (cam->params.colourBalance.balanceMode == 1) { do_command(cam, CPIA_COMMAND_SetColourBalance, 1, cam->params.colourBalance.redGain, @@ -2116,32 +2346,59 @@ static void dispatch_commands(struct cam_data *cam) do_command(cam, CPIA_COMMAND_SetColourBalance, 3, 0, 0, 0); } + if (cam->params.colourBalance.balanceMode == 2) { + do_command(cam, CPIA_COMMAND_SetColourBalance, + 2, 0, 0, 0); + } + if (cam->params.colourBalance.balanceMode == 3) { + do_command(cam, CPIA_COMMAND_SetColourBalance, + 3, 0, 0, 0); + } } + if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET) + do_command(cam, CPIA_COMMAND_SetCompressionTarget, + cam->params.compressionTarget.frTargeting, + cam->params.compressionTarget.targetFR, + cam->params.compressionTarget.targetQ, 0); + + if (cam->cmd_queue & COMMAND_SETYUVTHRESH) + do_command(cam, CPIA_COMMAND_SetYUVThresh, + cam->params.yuvThreshold.yThreshold, + cam->params.yuvThreshold.uvThreshold, 0, 0); + + if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS) + do_command_extended(cam, CPIA_COMMAND_SetCompressionParams, + 0, 0, 0, 0, + cam->params.compressionParams.hysteresis, + cam->params.compressionParams.threshMax, + cam->params.compressionParams.smallStep, + cam->params.compressionParams.largeStep, + cam->params.compressionParams.decimationHysteresis, + cam->params.compressionParams.frDiffStepThresh, + cam->params.compressionParams.qDiffStepThresh, + cam->params.compressionParams.decimationThreshMod); + + if (cam->cmd_queue & COMMAND_SETCOMPRESSION) + do_command(cam, CPIA_COMMAND_SetCompression, + cam->params.compression.mode, + cam->params.compression.decimation, 0, 0); + if (cam->cmd_queue & COMMAND_SETSENSORFPS) do_command(cam, CPIA_COMMAND_SetSensorFPS, cam->params.sensorFps.divisor, cam->params.sensorFps.baserate, 0, 0); - if (cam->cmd_queue & COMMAND_SETAPCOR) - do_command(cam, CPIA_COMMAND_SetApcor, - cam->params.apcor.gain1, - cam->params.apcor.gain2, - cam->params.apcor.gain4, - cam->params.apcor.gain8); - if (cam->cmd_queue & COMMAND_SETFLICKERCTRL) do_command(cam, CPIA_COMMAND_SetFlickerCtrl, cam->params.flickerControl.flickerMode, cam->params.flickerControl.coarseJump, - cam->params.flickerControl.allowableOverExposure, 0); + abs(cam->params.flickerControl.allowableOverExposure), + 0); - if (cam->cmd_queue & COMMAND_SETVLOFFSET) - do_command(cam, CPIA_COMMAND_SetVLOffset, - cam->params.vlOffset.gain1, - cam->params.vlOffset.gain2, - cam->params.vlOffset.gain4, - cam->params.vlOffset.gain8); + if (cam->cmd_queue & COMMAND_SETECPTIMING) + do_command(cam, CPIA_COMMAND_SetECPTiming, + cam->params.ecpTiming, 0, 0, 0); if (cam->cmd_queue & COMMAND_PAUSE) do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0); @@ -2149,20 +2406,416 @@ static void dispatch_commands(struct cam_data *cam) if (cam->cmd_queue & COMMAND_RESUME) init_stream_cap(cam); - if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected) { - int p1 = (cam->params.qx3.bottomlight == 0) << 1; - int p2 = (cam->params.qx3.toplight == 0) << 3; - do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0); - do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0); - } + if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected) + { + int p1 = (cam->params.qx3.bottomlight == 0) << 1; + int p2 = (cam->params.qx3.toplight == 0) << 3; + do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0); + do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0); + } - up(&cam->param_lock); cam->cmd_queue = COMMAND_NONE; + up(&cam->param_lock); return; } + + +static void set_flicker(struct cam_params *params, volatile u32 *command_flags, + int on) +{ + /* Everything in here is from the Windows driver */ +#define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \ + params->version.firmwareRevision == (y)) +/* define for compgain calculation */ +#define COMPGAIN(base, curexp, newexp) \ + (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5) +#define EXP_FROM_COMP(basecomp, curcomp, curexp) \ + (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128)) + int currentexp = params->exposure.coarseExpLo + + params->exposure.coarseExpHi*256; + int startexp; + if (on) { + int cj = params->flickerControl.coarseJump; + params->flickerControl.flickerMode = 1; + params->flickerControl.disabled = 0; + if(params->exposure.expMode != 2) + *command_flags |= COMMAND_SETEXPOSURE; + params->exposure.expMode = 2; + currentexp = currentexp << params->exposure.gain; + params->exposure.gain = 0; + /* round down current exposure to nearest value */ + startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj; + if(startexp < 1) + startexp = 1; + startexp = (startexp * cj) - 1; + if(FIRMWARE_VERSION(1,2)) + while(startexp > MAX_EXP_102) + startexp -= cj; + else + while(startexp > MAX_EXP) + startexp -= cj; + params->exposure.coarseExpLo = startexp & 0xff; + params->exposure.coarseExpHi = startexp >> 8; + if (currentexp > startexp) { + if (currentexp > (2 * startexp)) + currentexp = 2 * startexp; + params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp); + params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp); + params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp); + params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp); + } else { + params->exposure.redComp = COMP_RED; + params->exposure.green1Comp = COMP_GREEN1; + params->exposure.green2Comp = COMP_GREEN2; + params->exposure.blueComp = COMP_BLUE; + } + if(FIRMWARE_VERSION(1,2)) + params->exposure.compMode = 0; + else + params->exposure.compMode = 1; + + params->apcor.gain1 = 0x18; + params->apcor.gain2 = 0x18; + params->apcor.gain4 = 0x16; + params->apcor.gain8 = 0x14; + *command_flags |= COMMAND_SETAPCOR; + } else { + params->flickerControl.flickerMode = 0; + params->flickerControl.disabled = 1; + /* Coarse = average of equivalent coarse for each comp channel */ + startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp); + startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp); + startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp); + startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp); + startexp = startexp >> 2; + while(startexp > MAX_EXP && + params->exposure.gain < params->exposure.gainMode-1) { + startexp = startexp >> 1; + ++params->exposure.gain; + } + if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102) + startexp = MAX_EXP_102; + if(startexp > MAX_EXP) + startexp = MAX_EXP; + params->exposure.coarseExpLo = startexp&0xff; + params->exposure.coarseExpHi = startexp >> 8; + params->exposure.redComp = COMP_RED; + params->exposure.green1Comp = COMP_GREEN1; + params->exposure.green2Comp = COMP_GREEN2; + params->exposure.blueComp = COMP_BLUE; + params->exposure.compMode = 1; + *command_flags |= COMMAND_SETEXPOSURE; + params->apcor.gain1 = 0x18; + params->apcor.gain2 = 0x16; + params->apcor.gain4 = 0x24; + params->apcor.gain8 = 0x34; + *command_flags |= COMMAND_SETAPCOR; + } + params->vlOffset.gain1 = 20; + params->vlOffset.gain2 = 24; + params->vlOffset.gain4 = 26; + params->vlOffset.gain8 = 26; + *command_flags |= COMMAND_SETVLOFFSET; +#undef FIRMWARE_VERSION +#undef EXP_FROM_COMP +#undef COMPGAIN +} + +#define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \ + cam->params.version.firmwareRevision == (y)) +/* monitor the exposure and adjust the sensor frame rate if needed */ +static void monitor_exposure(struct cam_data *cam) +{ + u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8]; + int retval, light_exp, dark_exp, very_dark_exp; + int old_exposure, new_exposure, framerate; + + /* get necessary stats and register settings from camera */ + /* do_command can't handle this, so do it ourselves */ + cmd[0] = CPIA_COMMAND_ReadVPRegs>>8; + cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff; + cmd[2] = 30; + cmd[3] = 4; + cmd[4] = 9; + cmd[5] = 8; + cmd[6] = 8; + cmd[7] = 0; + retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data); + if (retval) { + LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n", + retval); + return; + } + exp_acc = data[0]; + bcomp = data[1]; + gain = data[2]; + coarseL = data[3]; + + down(&cam->param_lock); + light_exp = cam->params.colourParams.brightness + + TC - 50 + EXP_ACC_LIGHT; + if(light_exp > 255) + light_exp = 255; + dark_exp = cam->params.colourParams.brightness + + TC - 50 - EXP_ACC_DARK; + if(dark_exp < 0) + dark_exp = 0; + very_dark_exp = dark_exp/2; + + old_exposure = cam->params.exposure.coarseExpHi * 256 + + cam->params.exposure.coarseExpLo; + + if(!cam->params.flickerControl.disabled) { + /* Flicker control on */ + int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102; + bcomp += 128; /* decode */ + if(bcomp >= max_comp && exp_acc < dark_exp) { + /* dark */ + if(exp_acc < very_dark_exp) { + /* very dark */ + if(cam->exposure_status == EXPOSURE_VERY_DARK) + ++cam->exposure_count; + else { + cam->exposure_status = EXPOSURE_VERY_DARK; + cam->exposure_count = 1; + } + } else { + /* just dark */ + if(cam->exposure_status == EXPOSURE_DARK) + ++cam->exposure_count; + else { + cam->exposure_status = EXPOSURE_DARK; + cam->exposure_count = 1; + } + } + } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) { + /* light */ + if(old_exposure <= VERY_LOW_EXP) { + /* very light */ + if(cam->exposure_status == EXPOSURE_VERY_LIGHT) + ++cam->exposure_count; + else { + cam->exposure_status = EXPOSURE_VERY_LIGHT; + cam->exposure_count = 1; + } + } else { + /* just light */ + if(cam->exposure_status == EXPOSURE_LIGHT) + ++cam->exposure_count; + else { + cam->exposure_status = EXPOSURE_LIGHT; + cam->exposure_count = 1; + } + } + } else { + /* not dark or light */ + cam->exposure_status = EXPOSURE_NORMAL; + } + } else { + /* Flicker control off */ + if(old_exposure >= MAX_EXP && exp_acc < dark_exp) { + /* dark */ + if(exp_acc < very_dark_exp) { + /* very dark */ + if(cam->exposure_status == EXPOSURE_VERY_DARK) + ++cam->exposure_count; + else { + cam->exposure_status = EXPOSURE_VERY_DARK; + cam->exposure_count = 1; + } + } else { + /* just dark */ + if(cam->exposure_status == EXPOSURE_DARK) + ++cam->exposure_count; + else { + cam->exposure_status = EXPOSURE_DARK; + cam->exposure_count = 1; + } + } + } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) { + /* light */ + if(old_exposure <= VERY_LOW_EXP) { + /* very light */ + if(cam->exposure_status == EXPOSURE_VERY_LIGHT) + ++cam->exposure_count; + else { + cam->exposure_status = EXPOSURE_VERY_LIGHT; + cam->exposure_count = 1; + } + } else { + /* just light */ + if(cam->exposure_status == EXPOSURE_LIGHT) + ++cam->exposure_count; + else { + cam->exposure_status = EXPOSURE_LIGHT; + cam->exposure_count = 1; + } + } + } else { + /* not dark or light */ + cam->exposure_status = EXPOSURE_NORMAL; + } + } + + framerate = cam->fps; + if(framerate > 30 || framerate < 1) + framerate = 1; + + if(!cam->params.flickerControl.disabled) { + /* Flicker control on */ + if((cam->exposure_status == EXPOSURE_VERY_DARK || + cam->exposure_status == EXPOSURE_DARK) && + cam->exposure_count >= DARK_TIME*framerate && + cam->params.sensorFps.divisor < 3) { + + /* dark for too long */ + ++cam->params.sensorFps.divisor; + cam->cmd_queue |= COMMAND_SETSENSORFPS; + + cam->params.flickerControl.coarseJump = + flicker_jumps[cam->mainsFreq] + [cam->params.sensorFps.baserate] + [cam->params.sensorFps.divisor]; + cam->cmd_queue |= COMMAND_SETFLICKERCTRL; + + new_exposure = cam->params.flickerControl.coarseJump-1; + while(new_exposure < old_exposure/2) + new_exposure += cam->params.flickerControl.coarseJump; + cam->params.exposure.coarseExpLo = new_exposure & 0xff; + cam->params.exposure.coarseExpHi = new_exposure >> 8; + cam->cmd_queue |= COMMAND_SETEXPOSURE; + cam->exposure_status = EXPOSURE_NORMAL; + LOG("Automatically decreasing sensor_fps\n"); + + } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT || + cam->exposure_status == EXPOSURE_LIGHT) && + cam->exposure_count >= LIGHT_TIME*framerate && + cam->params.sensorFps.divisor > 0) { + + /* light for too long */ + int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ; + + --cam->params.sensorFps.divisor; + cam->cmd_queue |= COMMAND_SETSENSORFPS; + + cam->params.flickerControl.coarseJump = + flicker_jumps[cam->mainsFreq] + [cam->params.sensorFps.baserate] + [cam->params.sensorFps.divisor]; + cam->cmd_queue |= COMMAND_SETFLICKERCTRL; + + new_exposure = cam->params.flickerControl.coarseJump-1; + while(new_exposure < 2*old_exposure && + new_exposure+ + cam->params.flickerControl.coarseJump < max_exp) + new_exposure += cam->params.flickerControl.coarseJump; + cam->params.exposure.coarseExpLo = new_exposure & 0xff; + cam->params.exposure.coarseExpHi = new_exposure >> 8; + cam->cmd_queue |= COMMAND_SETEXPOSURE; + cam->exposure_status = EXPOSURE_NORMAL; + LOG("Automatically increasing sensor_fps\n"); + } + } else { + /* Flicker control off */ + if((cam->exposure_status == EXPOSURE_VERY_DARK || + cam->exposure_status == EXPOSURE_DARK) && + cam->exposure_count >= DARK_TIME*framerate && + cam->params.sensorFps.divisor < 3) { + + /* dark for too long */ + ++cam->params.sensorFps.divisor; + cam->cmd_queue |= COMMAND_SETSENSORFPS; + + if(cam->params.exposure.gain > 0) { + --cam->params.exposure.gain; + cam->cmd_queue |= COMMAND_SETEXPOSURE; + } + cam->exposure_status = EXPOSURE_NORMAL; + LOG("Automatically decreasing sensor_fps\n"); + + } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT || + cam->exposure_status == EXPOSURE_LIGHT) && + cam->exposure_count >= LIGHT_TIME*framerate && + cam->params.sensorFps.divisor > 0) { + + /* light for too long */ + --cam->params.sensorFps.divisor; + cam->cmd_queue |= COMMAND_SETSENSORFPS; + + if(cam->params.exposure.gain < + cam->params.exposure.gainMode-1) { + ++cam->params.exposure.gain; + cam->cmd_queue |= COMMAND_SETEXPOSURE; + } + cam->exposure_status = EXPOSURE_NORMAL; + LOG("Automatically increasing sensor_fps\n"); + } + } + up(&cam->param_lock); +} + +/*-----------------------------------------------------------------*/ +/* if flicker is switched off, this function switches it back on.It checks, + however, that conditions are suitable before restarting it. + This should only be called for firmware version 1.2. + + It also adjust the colour balance when an exposure step is detected - as + long as flicker is running +*/ +static void restart_flicker(struct cam_data *cam) +{ + int cam_exposure, old_exp; + if(!FIRMWARE_VERSION(1,2)) + return; + down(&cam->param_lock); + if(cam->params.flickerControl.flickerMode == 0 || + cam->raw_image[39] == 0) { + up(&cam->param_lock); + return; + } + cam_exposure = cam->raw_image[39]*2; + old_exp = cam->params.exposure.coarseExpLo + + cam->params.exposure.coarseExpHi*256; + /* + see how far away camera exposure is from a valid + flicker exposure value + */ + cam_exposure %= cam->params.flickerControl.coarseJump; + if(!cam->params.flickerControl.disabled && + cam_exposure <= cam->params.flickerControl.coarseJump - 3) { + /* Flicker control auto-disabled */ + cam->params.flickerControl.disabled = 1; + } + + if(cam->params.flickerControl.disabled && + cam->params.flickerControl.flickerMode && + old_exp > cam->params.flickerControl.coarseJump + + ROUND_UP_EXP_FOR_FLICKER) { + /* exposure is now high enough to switch + flicker control back on */ + set_flicker(&cam->params, &cam->cmd_queue, 1); + if((cam->cmd_queue & COMMAND_SETEXPOSURE) && + cam->params.exposure.expMode == 2) + cam->exposure_status = EXPOSURE_NORMAL; + + } + up(&cam->param_lock); +} +#undef FIRMWARE_VERSION + +static int clear_stall(struct cam_data *cam) +{ + /* FIXME: Does this actually work? */ + LOG("Clearing stall\n"); + + cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0); + do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0); + return cam->params.status.streamState != STREAM_PAUSED; +} + /* kernel thread function to read image from camera */ -static void fetch_frame(void *data) +static int fetch_frame(void *data) { int image_size, retry; struct cam_data *cam = (struct cam_data *)data; @@ -2179,41 +2832,54 @@ static void fetch_frame(void *data) /* load first frame always uncompressed */ if (cam->first_frame && - cam->params.compression.mode != CPIA_COMPRESSION_NONE) + cam->params.compression.mode != CPIA_COMPRESSION_NONE) { do_command(cam, CPIA_COMMAND_SetCompression, CPIA_COMPRESSION_NONE, NO_DECIMATION, 0, 0); + /* Trial & error - Discarding a frame prevents the + first frame from having an error in the data. */ + do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0); + } /* init camera upload */ - if (do_command(cam, CPIA_COMMAND_SetGrabMode, - CPIA_GRAB_CONTINUOUS, 0, 0, 0)) - continue; - if (do_command(cam, CPIA_COMMAND_GrabFrame, 0, cam->params.streamStartLine, 0, 0)) continue; if (cam->ops->wait_for_stream_ready) { /* loop until image ready */ + int count = 0; do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0); while (cam->params.status.streamState != STREAM_READY) { + if(++count > READY_TIMEOUT) + break; + if(cam->params.status.streamState == + STREAM_PAUSED) { + /* Bad news */ + if(!clear_stall(cam)) + return -EIO; + } + cond_resched(); + /* sleep for 10 ms, hopefully ;) */ current->state = TASK_INTERRUPTIBLE; - /* sleep for 10 ms, hopefully ;) */ schedule_timeout(10*HZ/1000); if (signal_pending(current)) - return; + return -EINTR; do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); } + if(cam->params.status.streamState != STREAM_READY) { + continue; + } } - /* grab image from camera */ cond_resched(); + /* grab image from camera */ oldjif = jiffies; image_size = cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0); @@ -2227,6 +2893,14 @@ static void fetch_frame(void *data) cam->transfer_rate = diff==0 ? rate : rate/diff; /* diff==0 ? unlikely but possible */ + /* Switch flicker control back on if it got turned off */ + restart_flicker(cam); + + /* If AEC is enabled, monitor the exposure and + adjust the sensor frame rate if needed */ + if(cam->params.exposure.expMode == 2) + monitor_exposure(cam); + /* camera idle now so dispatch queued commands */ dispatch_commands(cam); @@ -2238,12 +2912,28 @@ static void fetch_frame(void *data) /* decompress and convert image to by copying it from * raw_image to decompressed_frame */ + cond_resched(); cam->image_size = parse_picture(cam, image_size); - if (cam->image_size <= 0) + if (cam->image_size <= 0) { DBG("parse_picture failed %d\n", cam->image_size); - else + if(cam->params.compression.mode != + CPIA_COMPRESSION_NONE) { + /* Compression may not work right if we + had a bad frame, get the next one + uncompressed. */ + cam->first_frame = 1; + do_command(cam, CPIA_COMMAND_SetGrabMode, + CPIA_GRAB_SINGLE, 0, 0, 0); + /* FIXME: Trial & error - need up to 70ms for + the grab mode change to complete ? */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(70*HZ / 1000); + if (signal_pending(current)) + return -EINTR; + } + } else break; } @@ -2257,66 +2947,51 @@ static void fetch_frame(void *data) } else cam->decompressed_frame.state = FRAME_DONE; -#if 0 - if (cam->first_frame && - cam->params.compression.mode != CPIA_COMPRESSION_NONE) { - cam->first_frame = 0; - cam->cmd_queue |= COMMAND_SETCOMPRESSION; - } -#else if (cam->first_frame) { cam->first_frame = 0; - cam->cmd_queue |= COMMAND_SETCOMPRESSION; - cam->cmd_queue |= COMMAND_SETEXPOSURE; + do_command(cam, CPIA_COMMAND_SetCompression, + cam->params.compression.mode, + cam->params.compression.decimation, 0, 0); + + /* Switch from single-grab to continuous grab */ + do_command(cam, CPIA_COMMAND_SetGrabMode, + CPIA_GRAB_CONTINUOUS, 0, 0, 0); } -#endif + return 0; } + return -EIO; } static int capture_frame(struct cam_data *cam, struct video_mmap *vm) { - int retval = 0; - if (!cam->frame_buf) { /* we do lazy allocation */ - if ((retval = allocate_frame_buf(cam))) - return retval; + int err; + if ((err = allocate_frame_buf(cam))) + return err; } - /* FIXME: the first frame seems to be captured by the camera - without regards to any initial settings, so we throw away - that one, the next one is generated with our settings - (exposure, color balance, ...) - */ - if (cam->first_frame) { - cam->curframe = vm->frame; - cam->frame[cam->curframe].state = FRAME_READY; - fetch_frame(cam); - if (cam->frame[cam->curframe].state != FRAME_DONE) - retval = -EIO; - } cam->curframe = vm->frame; cam->frame[cam->curframe].state = FRAME_READY; - fetch_frame(cam); - if (cam->frame[cam->curframe].state != FRAME_DONE) - retval=-EIO; - - return retval; + return fetch_frame(cam); } static int goto_high_power(struct cam_data *cam) { if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0)) - return -1; - mdelay(100); /* windows driver does it too */ + return -EIO; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(40*HZ/1000); /* windows driver does it too */ + if(signal_pending(current)) + return -EINTR; if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) - return -1; + return -EIO; if (cam->params.status.systemState == HI_POWER_STATE) { DBG("camera now in HIGH power state\n"); return 0; } printstatus(cam); - return -1; + return -EIO; } static int goto_low_power(struct cam_data *cam) @@ -2335,8 +3010,10 @@ static int goto_low_power(struct cam_data *cam) static void save_camera_state(struct cam_data *cam) { - do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); - do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); + if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE)) + do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); + if(!(cam->cmd_queue & COMMAND_SETEXPOSURE)) + do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); DBG("%d/%d/%d/%d/%d/%d/%d/%d\n", cam->params.exposure.gain, @@ -2353,44 +3030,8 @@ static void save_camera_state(struct cam_data *cam) cam->params.colourBalance.blueGain); } -static void set_camera_state(struct cam_data *cam) +static int set_camera_state(struct cam_data *cam) { - if(cam->params.colourBalance.balanceModeIsAuto) { - do_command(cam, CPIA_COMMAND_SetColourBalance, - 2, 0, 0, 0); - } else { - do_command(cam, CPIA_COMMAND_SetColourBalance, - 1, - cam->params.colourBalance.redGain, - cam->params.colourBalance.greenGain, - cam->params.colourBalance.blueGain); - do_command(cam, CPIA_COMMAND_SetColourBalance, - 3, 0, 0, 0); - } - - - do_command_extended(cam, CPIA_COMMAND_SetExposure, - cam->params.exposure.gainMode, 1, 1, - cam->params.exposure.centreWeight, - cam->params.exposure.gain, - cam->params.exposure.fineExp, - cam->params.exposure.coarseExpLo, - cam->params.exposure.coarseExpHi, - cam->params.exposure.redComp, - cam->params.exposure.green1Comp, - cam->params.exposure.green2Comp, - cam->params.exposure.blueComp); - do_command_extended(cam, CPIA_COMMAND_SetExposure, - 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0); - - if (!cam->params.exposure.gainMode) - cam->params.exposure.gainMode = 2; - if (!cam->params.exposure.expMode) - cam->params.exposure.expMode = 2; - if (!cam->params.exposure.centreWeight) - cam->params.exposure.centreWeight = 1; - cam->cmd_queue = COMMAND_SETCOMPRESSION | COMMAND_SETCOMPRESSIONTARGET | COMMAND_SETCOLOURPARAMS | @@ -2398,18 +3039,29 @@ static void set_camera_state(struct cam_data *cam) COMMAND_SETYUVTHRESH | COMMAND_SETECPTIMING | COMMAND_SETCOMPRESSIONPARAMS | -#if 0 COMMAND_SETEXPOSURE | -#endif COMMAND_SETCOLOURBALANCE | COMMAND_SETSENSORFPS | COMMAND_SETAPCOR | COMMAND_SETFLICKERCTRL | COMMAND_SETVLOFFSET; + + do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0); dispatch_commands(cam); + + /* Wait 6 frames for the sensor to get all settings and + AEC/ACB to settle */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((6*(cam->params.sensorFps.baserate ? 33 : 40) * + (1 << cam->params.sensorFps.divisor) + 10) * + HZ / 1000); + + if(signal_pending(current)) + return -EINTR; + save_camera_state(cam); - return; + return 0; } static void get_version_information(struct cam_data *cam) @@ -2424,14 +3076,16 @@ static void get_version_information(struct cam_data *cam) /* initialize camera */ static int reset_camera(struct cam_data *cam) { + int err; /* Start the camera in low power mode */ if (goto_low_power(cam)) { if (cam->params.status.systemState != WARM_BOOT_STATE) return -ENODEV; /* FIXME: this is just dirty trial and error */ - reset_camera_struct(cam); - goto_high_power(cam); + err = goto_high_power(cam); + if(err) + return err; do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0); if (goto_low_power(cam)) return -ENODEV; @@ -2439,12 +3093,18 @@ static int reset_camera(struct cam_data *cam) /* procedure described in developer's guide p3-28 */ - /* Check the firmware version FIXME: should we check PNPID? */ + /* Check the firmware version. */ cam->params.version.firmwareVersion = 0; get_version_information(cam); if (cam->params.version.firmwareVersion != 1) return -ENODEV; + /* A bug in firmware 1-02 limits gainMode to 2 */ + if(cam->params.version.firmwareRevision <= 2 && + cam->params.exposure.gainMode > 2) { + cam->params.exposure.gainMode = 2; + } + /* set QX3 detected flag */ cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 && cam->params.pnpID.product == 0x0001); @@ -2458,8 +3118,9 @@ static int reset_camera(struct cam_data *cam) STREAM_NOT_READY, 0); /* GotoHiPower */ - if (goto_high_power(cam)) - return -ENODEV; + err = goto_high_power(cam); + if (err) + return err; /* Check the camera status */ if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) @@ -2492,9 +3153,13 @@ static int reset_camera(struct cam_data *cam) do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0); /* set camera to a known state */ - set_camera_state(cam); - - return 0; + return set_camera_state(cam); +} + +static void put_cam(struct cpia_camera_ops* ops) +{ + if (ops->owner) + __MOD_DEC_USE_COUNT(ops->owner); } /* ------------------------- V4L interface --------------------- */ @@ -2508,7 +3173,10 @@ static int cpia_open(struct inode *inode, struct file *file) DBG("Internal error, cam_data not found!\n"); return -ENODEV; } - + + if (!try_inc_mod_count(cam->ops->owner)) + return -ENODEV; + down(&cam->busy_lock); err = -EBUSY; if (cam->open_count > 0) { @@ -2522,7 +3190,7 @@ static int cpia_open(struct inode *inode, struct file *file) if (!cam->raw_image) goto oops; } - + if (!cam->decompressed_frame.data) { cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE); if (!cam->decompressed_frame.data) @@ -2539,6 +3207,9 @@ static int cpia_open(struct inode *inode, struct file *file) cam->ops->close(cam->lowlevel_data); goto oops; } + + if(signal_pending(current)) + return -EINTR; /* Set ownership of /proc/cpia/videoX to current user */ if(cam->proc_entry) @@ -2552,6 +3223,7 @@ static int cpia_open(struct inode *inode, struct file *file) ++cam->open_count; file->private_data = dev; + up(&cam->busy_lock); return 0; oops: @@ -2564,6 +3236,7 @@ static int cpia_open(struct inode *inode, struct file *file) cam->raw_image = NULL; } up(&cam->busy_lock); + put_cam(cam->ops); return err; } @@ -2591,6 +3264,8 @@ static int cpia_close(struct inode *inode, struct file *file) /* close cpia */ cam->ops->close(cam->lowlevel_data); + + put_cam(cam->ops); } if (--cam->open_count == 0) { @@ -2621,6 +3296,7 @@ static int cpia_read(struct file *file, char *buf, { struct video_device *dev = file->private_data; struct cam_data *cam = dev->priv; + int err; /* make this _really_ smp and multithread-safe */ if (down_interruptible(&cam->busy_lock)) @@ -2647,19 +3323,17 @@ static int cpia_read(struct file *file, char *buf, /* upload frame */ cam->decompressed_frame.state = FRAME_READY; cam->mmap_kludge=0; - fetch_frame(cam); - if (cam->decompressed_frame.state != FRAME_DONE) { - DBG("upload failed %d/%d\n", cam->decompressed_frame.count, - cam->decompressed_frame.state); + if((err = fetch_frame(cam)) != 0) { + DBG("ERROR from fetch_frame: %d\n", err); up(&cam->busy_lock); - return -EIO; + return err; } cam->decompressed_frame.state = FRAME_UNUSED; /* copy data to user space */ if (cam->decompressed_frame.count > count) { DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count, - count); + (unsigned long) count); up(&cam->busy_lock); return -EFAULT; } @@ -2698,7 +3372,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, DBG("VIDIOCGCAP\n"); strcpy(b->name, "CPiA Camera"); - b->type = VID_TYPE_CAPTURE; + b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; b->channels = 1; b->audios = 0; b->maxwidth = 352; /* VIDEOSIZE_CIF */ @@ -2754,8 +3428,8 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, DBG("VIDIOCSPICT\n"); /* check validity */ - DBG("palette: %d\n", vp.palette); - DBG("depth: %d\n", vp.depth); + DBG("palette: %d\n", vp->palette); + DBG("depth: %d\n", vp->depth); if (!valid_mode(vp->palette, vp->depth)) { retval = -EINVAL; break; @@ -2825,6 +3499,10 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, break; } cam->video_size = video_size; + + /* video size is changing, reset the subcapture area */ + memset(&cam->vc, 0, sizeof(cam->vc)); + set_vw_size(cam); DBG("%d / %d\n", cam->vw.width, cam->vw.height); cam->cmd_queue |= COMMAND_SETFORMAT; @@ -2904,6 +3582,10 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, } if (video_size != cam->video_size) { cam->video_size = video_size; + + /* video size is changing, reset the subcapture area */ + memset(&cam->vc, 0, sizeof(cam->vc)); + set_vw_size(cam); cam->cmd_queue |= COMMAND_SETFORMAT; dispatch_commands(cam); @@ -2946,6 +3628,77 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, break; } + case VIDIOCGCAPTURE: + DBG("VIDIOCGCAPTURE\n"); + if (copy_to_user(arg, &cam->vc, sizeof(struct video_capture))) + retval = -EFAULT; + break; + + case VIDIOCSCAPTURE: + { + struct video_capture vc; + + DBG("VIDIOCSCAPTURE\n"); + if (copy_from_user(&vc, arg, sizeof(vc))) { + retval = -EFAULT; + break; + } + + if (vc.decimation != 0) { /* How should this be used? */ + retval = -EINVAL; + break; + } + if (vc.flags != 0) { /* Even/odd grab not supported */ + retval = -EINVAL; + break; + } + + /* Clip to the resolution we can set for the ROI + (every 8 columns and 4 rows) */ + vc.x = vc.x & ~(__u32)7; + vc.y = vc.y & ~(__u32)3; + vc.width = vc.width & ~(__u32)7; + vc.height = vc.height & ~(__u32)3; + + if(vc.width == 0 || vc.height == 0 || + vc.x + vc.width > cam->vw.width || + vc.y + vc.height > cam->vw.height) { + retval = -EINVAL; + break; + } + + DBG("%d,%d/%dx%d\n", vc.x,vc.y,vc.width, vc.height); + + down(&cam->param_lock); + + cam->vc.x = vc.x; + cam->vc.y = vc.y; + cam->vc.width = vc.width; + cam->vc.height = vc.height; + + set_vw_size(cam); + cam->cmd_queue |= COMMAND_SETFORMAT; + + up(&cam->param_lock); + + /* setformat ignored by camera during streaming, + * so stop/dispatch/start */ + dispatch_commands(cam); + break; + } + + case VIDIOCGUNIT: + { + struct video_unit vu; + vu.video = cam->vdev.minor; + vu.vbi = VIDEO_NO_UNIT; + vu.radio = VIDEO_NO_UNIT; + vu.audio = VIDEO_NO_UNIT; + vu.teletext = VIDEO_NO_UNIT; + break; + } + + /* pointless to implement overlay with this camera */ case VIDIOCCAPTURE: case VIDIOCGFBUF: @@ -2966,7 +3719,6 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, break; } - up(&cam->param_lock); up(&cam->busy_lock); return retval; } @@ -3057,7 +3809,7 @@ static void reset_camera_struct(struct cam_data *cam) cam->params.colourParams.brightness = 50; cam->params.colourParams.contrast = 48; cam->params.colourParams.saturation = 50; - cam->params.exposure.gainMode = 2; + cam->params.exposure.gainMode = 4; cam->params.exposure.expMode = 2; /* AEC */ cam->params.exposure.compMode = 1; cam->params.exposure.centreWeight = 1; @@ -3065,27 +3817,31 @@ static void reset_camera_struct(struct cam_data *cam) cam->params.exposure.fineExp = 0; cam->params.exposure.coarseExpLo = 185; cam->params.exposure.coarseExpHi = 0; - cam->params.exposure.redComp = 220; - cam->params.exposure.green1Comp = 214; - cam->params.exposure.green2Comp = 214; - cam->params.exposure.blueComp = 230; - cam->params.colourBalance.balanceModeIsAuto = 1; + cam->params.exposure.redComp = COMP_RED; + cam->params.exposure.green1Comp = COMP_GREEN1; + cam->params.exposure.green2Comp = COMP_GREEN2; + cam->params.exposure.blueComp = COMP_BLUE; + cam->params.colourBalance.balanceMode = 2; /* ACB */ cam->params.colourBalance.redGain = 32; cam->params.colourBalance.greenGain = 6; cam->params.colourBalance.blueGain = 92; - cam->params.apcor.gain1 = 0x1c; - cam->params.apcor.gain2 = 0x1a; - cam->params.apcor.gain4 = 0x2d; - cam->params.apcor.gain8 = 0x2a; + cam->params.apcor.gain1 = 0x18; + cam->params.apcor.gain2 = 0x16; + cam->params.apcor.gain4 = 0x24; + cam->params.apcor.gain8 = 0x34; cam->params.flickerControl.flickerMode = 0; + cam->params.flickerControl.disabled = 1; + cam->params.flickerControl.coarseJump = flicker_jumps[cam->mainsFreq] [cam->params.sensorFps.baserate] [cam->params.sensorFps.divisor]; - cam->params.vlOffset.gain1 = 24; - cam->params.vlOffset.gain2 = 28; - cam->params.vlOffset.gain4 = 30; - cam->params.vlOffset.gain8 = 30; + cam->params.flickerControl.allowableOverExposure = + -find_over_exposure(cam->params.colourParams.brightness); + cam->params.vlOffset.gain1 = 20; + cam->params.vlOffset.gain2 = 24; + cam->params.vlOffset.gain4 = 26; + cam->params.vlOffset.gain8 = 26; cam->params.compressionParams.hysteresis = 3; cam->params.compressionParams.threshMax = 11; cam->params.compressionParams.smallStep = 1; @@ -3097,6 +3853,7 @@ static void reset_camera_struct(struct cam_data *cam) /* End of default values from Software Developer's Guide */ cam->transfer_rate = 0; + cam->exposure_status = EXPOSURE_NORMAL; /* Set Sensor FPS to 15fps. This seems better than 30fps * for indoor lighting. */ @@ -3131,17 +3888,21 @@ static void reset_camera_struct(struct cam_data *cam) cam->vp.depth = 24; /* to be set by user */ cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */ + cam->vc.x = 0; + cam->vc.y = 0; + cam->vc.width = 0; + cam->vc.height = 0; + cam->vw.x = 0; cam->vw.y = 0; set_vw_size(cam); cam->vw.chromakey = 0; - /* PP NOTE: my extension to use vw.flags for this, bear it! */ cam->vw.flags = 0; cam->vw.clipcount = 0; cam->vw.clips = NULL; cam->cmd_queue = COMMAND_NONE; - cam->first_frame = 0; + cam->first_frame = 1; return; } diff --git a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h index 7929e4926a91..721af46a4c3b 100644 --- a/drivers/media/video/cpia.h +++ b/drivers/media/video/cpia.h @@ -26,13 +26,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define CPIA_MAJ_VER 0 -#define CPIA_MIN_VER 8 -#define CPIA_PATCH_VER 1 +#define CPIA_MAJ_VER 1 +#define CPIA_MIN_VER 2 +#define CPIA_PATCH_VER 2 -#define CPIA_PP_MAJ_VER 0 -#define CPIA_PP_MIN_VER 8 -#define CPIA_PP_PATCH_VER 1 +#define CPIA_PP_MAJ_VER 1 +#define CPIA_PP_MIN_VER 2 +#define CPIA_PP_PATCH_VER 2 #define CPIA_MAX_FRAME_SIZE_UNALIGNED (352 * 288 * 4) /* CIF at RGB32 */ #define CPIA_MAX_FRAME_SIZE ((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */ @@ -93,6 +93,11 @@ struct cpia_camera_ops * is STREAM_READY before calling streamRead. */ int wait_for_stream_ready; + + /* + * Used to maintain lowlevel module usage counts + */ + struct module *owner; }; struct cpia_frame { @@ -150,7 +155,7 @@ struct cam_params { u8 blueComp; } exposure; struct { - u8 balanceModeIsAuto; + u8 balanceMode; u8 redGain; u8 greenGain; u8 blueGain; @@ -166,9 +171,10 @@ struct cam_params { u8 gain8; } apcor; struct { + u8 disabled; u8 flickerMode; u8 coarseJump; - u8 allowableOverExposure; + int allowableOverExposure; } flickerControl; struct { u8 gain1; @@ -261,6 +267,7 @@ struct cam_data { struct video_device vdev; /* v4l videodev */ struct video_picture vp; /* v4l camera settings */ struct video_window vw; /* v4l capture area */ + struct video_capture vc; /* v4l subcapture area */ /* mmap interface */ int curframe; /* the current frame to grab into */ @@ -271,6 +278,8 @@ struct cam_data { int first_frame; int mmap_kludge; /* 'wrong' byte order for mmap */ volatile u32 cmd_queue; /* queued commands */ + int exposure_status; /* EXPOSURE_* */ + int exposure_count; /* number of frames at this status */ }; /* cpia_register_camera is called by low level driver for each camera. @@ -382,15 +391,27 @@ void cpia_unregister_camera(struct cam_data *cam); #define VP_STATE_ACB_RMAX 0x40 #define VP_STATE_ACB_GMAX 0x80 +/* default (minimum) compensation values */ +#define COMP_RED 220 +#define COMP_GREEN1 214 +#define COMP_GREEN2 COMP_GREEN1 +#define COMP_BLUE 230 + +/* exposure status */ +#define EXPOSURE_VERY_LIGHT 0 +#define EXPOSURE_LIGHT 1 +#define EXPOSURE_NORMAL 2 +#define EXPOSURE_DARK 3 +#define EXPOSURE_VERY_DARK 4 + /* ErrorCode */ #define ERROR_FLICKER_BELOW_MIN_EXP 0x01 /*flicker exposure got below minimum exposure */ - #define ALOG(fmt,args...) printk(fmt, ##args) #define LOG(fmt,args...) ALOG(KERN_INFO __FILE__ ":%s(%d):" fmt, __FUNCTION__ , __LINE__ , ##args) #ifdef _CPIA_DEBUG_ -#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, lineno, ##args) -#define DBG(fmt,args...) ADBG((__LINE__), KERN_DEBUG __FILE__" (%ld):" __FUNCTION__ "(%d):" fmt, ##args) +#define ADBG(fmt,args...) printk(fmt, jiffies, ##args) +#define DBG(fmt,args...) ADBG(KERN_DEBUG __FILE__" (%ld):%s(%d):" fmt, __FUNCTION__, __LINE__ , ##args) #else #define DBG(fmn,args...) do {} while(0) #endif @@ -400,15 +421,19 @@ void cpia_unregister_camera(struct cam_data *cam); (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\ (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0); -static inline void cpia_add_to_list(struct cam_data* l, struct cam_data* drv) +static inline void cpia_add_to_list(struct cam_data** l, struct cam_data** drv_p) { - drv->next = l; - drv->previous = &l; - l = drv; + struct cam_data* drv; + drv = *drv_p; + drv->next = *l; + drv->previous = l; + *l = drv; } -static inline void cpia_remove_from_list(struct cam_data* drv) +static inline void cpia_remove_from_list(struct cam_data** drv_p) { + struct cam_data* drv; + drv = *drv_p; if (drv->previous != NULL) { if (drv->next != NULL) drv->next->previous = drv->previous; diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c index 0deb614dc11e..1e6902dc7936 100644 --- a/drivers/media/video/cpia_pp.c +++ b/drivers/media/video/cpia_pp.c @@ -157,7 +157,8 @@ static struct cpia_camera_ops cpia_pp_ops = cpia_pp_streamStop, cpia_pp_streamRead, cpia_pp_close, - 1 + 1, + THIS_MODULE }; static struct cam_data *cam_list; @@ -565,7 +566,7 @@ static int cpia_pp_register(struct parport *port) return -ENXIO; } spin_lock( &cam_list_lock_pp ); - cpia_add_to_list(cam_list, cpia); + cpia_add_to_list(&cam_list, &cpia); spin_unlock( &cam_list_lock_pp ); return 0; @@ -575,11 +576,11 @@ static void cpia_pp_detach (struct parport *port) { struct cam_data *cpia; - spin_lock( &cam_list_lock_pp ); for(cpia = cam_list; cpia != NULL; cpia = cpia->next) { struct pp_cam_entry *cam = cpia->lowlevel_data; if (cam && cam->port->number == port->number) { - cpia_remove_from_list(cpia); + spin_lock( &cam_list_lock_pp ); + cpia_remove_from_list(&cpia); spin_unlock( &cam_list_lock_pp ); cpia_unregister_camera(cpia); diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c index aae71451aeb7..3a68e91717de 100644 --- a/drivers/media/video/cpia_usb.c +++ b/drivers/media/video/cpia_usb.c @@ -100,7 +100,8 @@ static struct cpia_camera_ops cpia_usb_ops = { cpia_usb_streamStop, cpia_usb_streamRead, cpia_usb_close, - 0 + 0, + THIS_MODULE }; static struct cam_data *cam_list; @@ -548,7 +549,7 @@ static int cpia_probe(struct usb_interface *intf, } spin_lock( &cam_list_lock_usb ); - cpia_add_to_list(cam_list, cam); + cpia_add_to_list(&cam_list, &cam); spin_unlock( &cam_list_lock_usb ); dev_set_drvdata(&intf->dev, cam); @@ -602,7 +603,7 @@ static void cpia_disconnect(struct usb_interface *intf) ucpia = (struct usb_cpia *) cam->lowlevel_data; spin_lock( &cam_list_lock_usb ); - cpia_remove_from_list(cam); + cpia_remove_from_list(&cam); spin_unlock( &cam_list_lock_usb ); /* Don't even try to reset the altsetting if we're disconnected */ |
