Showing error 1124

User: Jiri Slaby
Error type: Double Lock
Error type description: Some lock is locked twice unintentionally in a sequence
File location: drivers/media/video/cpia.c
Line in file: 1649
Project: Linux Kernel
Project version: 2.6.28
Tools: Stanse (1.2)
Entered: 2012-04-29 14:49:11 UTC


Source:

   1/*
   2 * cpia CPiA driver
   3 *
   4 * Supports CPiA based Video Camera's.
   5 *
   6 * (C) Copyright 1999-2000 Peter Pregler
   7 * (C) Copyright 1999-2000 Scott J. Bertin
   8 * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
   9 * (C) Copyright 2000 STMicroelectronics
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or
  14 * (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24 */
  25
  26/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
  27/* #define _CPIA_DEBUG_  1 */
  28
  29
  30#include <linux/module.h>
  31#include <linux/init.h>
  32#include <linux/fs.h>
  33#include <linux/vmalloc.h>
  34#include <linux/slab.h>
  35#include <linux/proc_fs.h>
  36#include <linux/ctype.h>
  37#include <linux/pagemap.h>
  38#include <linux/delay.h>
  39#include <asm/io.h>
  40#include <linux/mutex.h>
  41
  42#include "cpia.h"
  43
  44static int video_nr = -1;
  45
  46#ifdef MODULE
  47module_param(video_nr, int, 0);
  48MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
  49MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
  50MODULE_LICENSE("GPL");
  51MODULE_SUPPORTED_DEVICE("video");
  52#endif
  53
  54static unsigned short colorspace_conv;
  55module_param(colorspace_conv, ushort, 0444);
  56MODULE_PARM_DESC(colorspace_conv,
  57                 " Colorspace conversion:"
  58                 "\n  0 = disable, 1 = enable"
  59                 "\n  Default value is 0"
  60                 );
  61
  62#define ABOUT "V4L-Driver for Vision CPiA based cameras"
  63
  64#define CPIA_MODULE_CPIA                        (0<<5)
  65#define CPIA_MODULE_SYSTEM                        (1<<5)
  66#define CPIA_MODULE_VP_CTRL                        (5<<5)
  67#define CPIA_MODULE_CAPTURE                        (6<<5)
  68#define CPIA_MODULE_DEBUG                        (7<<5)
  69
  70#define INPUT (DATA_IN << 8)
  71#define OUTPUT (DATA_OUT << 8)
  72
  73#define CPIA_COMMAND_GetCPIAVersion        (INPUT | CPIA_MODULE_CPIA | 1)
  74#define CPIA_COMMAND_GetPnPID                (INPUT | CPIA_MODULE_CPIA | 2)
  75#define CPIA_COMMAND_GetCameraStatus        (INPUT | CPIA_MODULE_CPIA | 3)
  76#define CPIA_COMMAND_GotoHiPower        (OUTPUT | CPIA_MODULE_CPIA | 4)
  77#define CPIA_COMMAND_GotoLoPower        (OUTPUT | CPIA_MODULE_CPIA | 5)
  78#define CPIA_COMMAND_GotoSuspend        (OUTPUT | CPIA_MODULE_CPIA | 7)
  79#define CPIA_COMMAND_GotoPassThrough        (OUTPUT | CPIA_MODULE_CPIA | 8)
  80#define CPIA_COMMAND_ModifyCameraStatus        (OUTPUT | CPIA_MODULE_CPIA | 10)
  81
  82#define CPIA_COMMAND_ReadVCRegs                (INPUT | CPIA_MODULE_SYSTEM | 1)
  83#define CPIA_COMMAND_WriteVCReg                (OUTPUT | CPIA_MODULE_SYSTEM | 2)
  84#define CPIA_COMMAND_ReadMCPorts        (INPUT | CPIA_MODULE_SYSTEM | 3)
  85#define CPIA_COMMAND_WriteMCPort        (OUTPUT | CPIA_MODULE_SYSTEM | 4)
  86#define CPIA_COMMAND_SetBaudRate        (OUTPUT | CPIA_MODULE_SYSTEM | 5)
  87#define CPIA_COMMAND_SetECPTiming        (OUTPUT | CPIA_MODULE_SYSTEM | 6)
  88#define CPIA_COMMAND_ReadIDATA                (INPUT | CPIA_MODULE_SYSTEM | 7)
  89#define CPIA_COMMAND_WriteIDATA                (OUTPUT | CPIA_MODULE_SYSTEM | 8)
  90#define CPIA_COMMAND_GenericCall        (OUTPUT | CPIA_MODULE_SYSTEM | 9)
  91#define CPIA_COMMAND_I2CStart                (OUTPUT | CPIA_MODULE_SYSTEM | 10)
  92#define CPIA_COMMAND_I2CStop                (OUTPUT | CPIA_MODULE_SYSTEM | 11)
  93#define CPIA_COMMAND_I2CWrite                (OUTPUT | CPIA_MODULE_SYSTEM | 12)
  94#define CPIA_COMMAND_I2CRead                (INPUT | CPIA_MODULE_SYSTEM | 13)
  95
  96#define CPIA_COMMAND_GetVPVersion        (INPUT | CPIA_MODULE_VP_CTRL | 1)
  97#define CPIA_COMMAND_ResetFrameCounter        (INPUT | CPIA_MODULE_VP_CTRL | 2)
  98#define CPIA_COMMAND_SetColourParams        (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
  99#define CPIA_COMMAND_SetExposure        (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
 100#define CPIA_COMMAND_SetColourBalance        (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
 101#define CPIA_COMMAND_SetSensorFPS        (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
 102#define CPIA_COMMAND_SetVPDefaults        (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
 103#define CPIA_COMMAND_SetApcor                (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
 104#define CPIA_COMMAND_SetFlickerCtrl        (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
 105#define CPIA_COMMAND_SetVLOffset        (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
 106#define CPIA_COMMAND_GetColourParams        (INPUT | CPIA_MODULE_VP_CTRL | 16)
 107#define CPIA_COMMAND_GetColourBalance        (INPUT | CPIA_MODULE_VP_CTRL | 17)
 108#define CPIA_COMMAND_GetExposure        (INPUT | CPIA_MODULE_VP_CTRL | 18)
 109#define CPIA_COMMAND_SetSensorMatrix        (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
 110#define CPIA_COMMAND_ColourBars                (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
 111#define CPIA_COMMAND_ReadVPRegs                (INPUT | CPIA_MODULE_VP_CTRL | 30)
 112#define CPIA_COMMAND_WriteVPReg                (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
 113
 114#define CPIA_COMMAND_GrabFrame                (OUTPUT | CPIA_MODULE_CAPTURE | 1)
 115#define CPIA_COMMAND_UploadFrame        (OUTPUT | CPIA_MODULE_CAPTURE | 2)
 116#define CPIA_COMMAND_SetGrabMode        (OUTPUT | CPIA_MODULE_CAPTURE | 3)
 117#define CPIA_COMMAND_InitStreamCap        (OUTPUT | CPIA_MODULE_CAPTURE | 4)
 118#define CPIA_COMMAND_FiniStreamCap        (OUTPUT | CPIA_MODULE_CAPTURE | 5)
 119#define CPIA_COMMAND_StartStreamCap        (OUTPUT | CPIA_MODULE_CAPTURE | 6)
 120#define CPIA_COMMAND_EndStreamCap        (OUTPUT | CPIA_MODULE_CAPTURE | 7)
 121#define CPIA_COMMAND_SetFormat                (OUTPUT | CPIA_MODULE_CAPTURE | 8)
 122#define CPIA_COMMAND_SetROI                (OUTPUT | CPIA_MODULE_CAPTURE | 9)
 123#define CPIA_COMMAND_SetCompression        (OUTPUT | CPIA_MODULE_CAPTURE | 10)
 124#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
 125#define CPIA_COMMAND_SetYUVThresh        (OUTPUT | CPIA_MODULE_CAPTURE | 12)
 126#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
 127#define CPIA_COMMAND_DiscardFrame        (OUTPUT | CPIA_MODULE_CAPTURE | 14)
 128#define CPIA_COMMAND_GrabReset                (OUTPUT | CPIA_MODULE_CAPTURE | 15)
 129
 130#define CPIA_COMMAND_OutputRS232        (OUTPUT | CPIA_MODULE_DEBUG | 1)
 131#define CPIA_COMMAND_AbortProcess        (OUTPUT | CPIA_MODULE_DEBUG | 4)
 132#define CPIA_COMMAND_SetDramPage        (OUTPUT | CPIA_MODULE_DEBUG | 5)
 133#define CPIA_COMMAND_StartDramUpload        (OUTPUT | CPIA_MODULE_DEBUG | 6)
 134#define CPIA_COMMAND_StartDummyDtream        (OUTPUT | CPIA_MODULE_DEBUG | 8)
 135#define CPIA_COMMAND_AbortStream        (OUTPUT | CPIA_MODULE_DEBUG | 9)
 136#define CPIA_COMMAND_DownloadDRAM        (OUTPUT | CPIA_MODULE_DEBUG | 10)
 137#define CPIA_COMMAND_Null                (OUTPUT | CPIA_MODULE_DEBUG | 11)
 138
 139enum {
 140        FRAME_READY,                /* Ready to grab into */
 141        FRAME_GRABBING,                /* In the process of being grabbed into */
 142        FRAME_DONE,                /* Finished grabbing, but not been synced yet */
 143        FRAME_UNUSED,                /* Unused (no MCAPTURE) */
 144};
 145
 146#define COMMAND_NONE                        0x0000
 147#define COMMAND_SETCOMPRESSION                0x0001
 148#define COMMAND_SETCOMPRESSIONTARGET        0x0002
 149#define COMMAND_SETCOLOURPARAMS                0x0004
 150#define COMMAND_SETFORMAT                0x0008
 151#define COMMAND_PAUSE                        0x0010
 152#define COMMAND_RESUME                        0x0020
 153#define COMMAND_SETYUVTHRESH                0x0040
 154#define COMMAND_SETECPTIMING                0x0080
 155#define COMMAND_SETCOMPRESSIONPARAMS        0x0100
 156#define COMMAND_SETEXPOSURE                0x0200
 157#define COMMAND_SETCOLOURBALANCE        0x0400
 158#define COMMAND_SETSENSORFPS                0x0800
 159#define COMMAND_SETAPCOR                0x1000
 160#define COMMAND_SETFLICKERCTRL                0x2000
 161#define COMMAND_SETVLOFFSET                0x4000
 162#define COMMAND_SETLIGHTS                0x8000
 163
 164#define ROUND_UP_EXP_FOR_FLICKER 15
 165
 166/* Constants for automatic frame rate adjustment */
 167#define MAX_EXP       302
 168#define MAX_EXP_102   255
 169#define LOW_EXP       140
 170#define VERY_LOW_EXP   70
 171#define TC             94
 172#define        EXP_ACC_DARK   50
 173#define        EXP_ACC_LIGHT  90
 174#define HIGH_COMP_102 160
 175#define MAX_COMP      239
 176#define DARK_TIME       3
 177#define LIGHT_TIME      3
 178
 179/* Maximum number of 10ms loops to wait for the stream to become ready */
 180#define READY_TIMEOUT 100
 181
 182/* Developer's Guide Table 5 p 3-34
 183 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
 184static u8 flicker_jumps[2][2][4] =
 185{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
 186  { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
 187};
 188
 189/* forward declaration of local function */
 190static void reset_camera_struct(struct cam_data *cam);
 191static int find_over_exposure(int brightness);
 192static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
 193                        int on);
 194
 195
 196/**********************************************************************
 197 *
 198 * Memory management
 199 *
 200 **********************************************************************/
 201static void *rvmalloc(unsigned long size)
 202{
 203        void *mem;
 204        unsigned long adr;
 205
 206        size = PAGE_ALIGN(size);
 207        mem = vmalloc_32(size);
 208        if (!mem)
 209                return NULL;
 210
 211        memset(mem, 0, size); /* Clear the ram out, no junk to the user */
 212        adr = (unsigned long) mem;
 213        while (size > 0) {
 214                SetPageReserved(vmalloc_to_page((void *)adr));
 215                adr += PAGE_SIZE;
 216                size -= PAGE_SIZE;
 217        }
 218
 219        return mem;
 220}
 221
 222static void rvfree(void *mem, unsigned long size)
 223{
 224        unsigned long adr;
 225
 226        if (!mem)
 227                return;
 228
 229        adr = (unsigned long) mem;
 230        while ((long) size > 0) {
 231                ClearPageReserved(vmalloc_to_page((void *)adr));
 232                adr += PAGE_SIZE;
 233                size -= PAGE_SIZE;
 234        }
 235        vfree(mem);
 236}
 237
 238/**********************************************************************
 239 *
 240 * /proc interface
 241 *
 242 **********************************************************************/
 243#ifdef CONFIG_PROC_FS
 244static struct proc_dir_entry *cpia_proc_root=NULL;
 245
 246static int cpia_read_proc(char *page, char **start, off_t off,
 247                          int count, int *eof, void *data)
 248{
 249        char *out = page;
 250        int len, tmp;
 251        struct cam_data *cam = data;
 252        char tmpstr[29];
 253
 254        /* IMPORTANT: This output MUST be kept under PAGE_SIZE
 255         *            or we need to get more sophisticated. */
 256
 257        out += sprintf(out, "read-only\n-----------------------\n");
 258        out += sprintf(out, "V4L Driver version:       %d.%d.%d\n",
 259                       CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
 260        out += sprintf(out, "CPIA Version:             %d.%02d (%d.%d)\n",
 261                       cam->params.version.firmwareVersion,
 262                       cam->params.version.firmwareRevision,
 263                       cam->params.version.vcVersion,
 264                       cam->params.version.vcRevision);
 265        out += sprintf(out, "CPIA PnP-ID:              %04x:%04x:%04x\n",
 266                       cam->params.pnpID.vendor, cam->params.pnpID.product,
 267                       cam->params.pnpID.deviceRevision);
 268        out += sprintf(out, "VP-Version:               %d.%d %04x\n",
 269                       cam->params.vpVersion.vpVersion,
 270                       cam->params.vpVersion.vpRevision,
 271                       cam->params.vpVersion.cameraHeadID);
 272
 273        out += sprintf(out, "system_state:             %#04x\n",
 274                       cam->params.status.systemState);
 275        out += sprintf(out, "grab_state:               %#04x\n",
 276                       cam->params.status.grabState);
 277        out += sprintf(out, "stream_state:             %#04x\n",
 278                       cam->params.status.streamState);
 279        out += sprintf(out, "fatal_error:              %#04x\n",
 280                       cam->params.status.fatalError);
 281        out += sprintf(out, "cmd_error:                %#04x\n",
 282                       cam->params.status.cmdError);
 283        out += sprintf(out, "debug_flags:              %#04x\n",
 284                       cam->params.status.debugFlags);
 285        out += sprintf(out, "vp_status:                %#04x\n",
 286                       cam->params.status.vpStatus);
 287        out += sprintf(out, "error_code:               %#04x\n",
 288                       cam->params.status.errorCode);
 289        /* QX3 specific entries */
 290        if (cam->params.qx3.qx3_detected) {
 291                out += sprintf(out, "button:                   %4d\n",
 292                               cam->params.qx3.button);
 293                out += sprintf(out, "cradled:                  %4d\n",
 294                               cam->params.qx3.cradled);
 295        }
 296        out += sprintf(out, "video_size:               %s\n",
 297                       cam->params.format.videoSize == VIDEOSIZE_CIF ?
 298                       "CIF " : "QCIF");
 299        out += sprintf(out, "roi:                      (%3d, %3d) to (%3d, %3d)\n",
 300                       cam->params.roi.colStart*8,
 301                       cam->params.roi.rowStart*4,
 302                       cam->params.roi.colEnd*8,
 303                       cam->params.roi.rowEnd*4);
 304        out += sprintf(out, "actual_fps:               %3d\n", cam->fps);
 305        out += sprintf(out, "transfer_rate:            %4dkB/s\n",
 306                       cam->transfer_rate);
 307
 308        out += sprintf(out, "\nread-write\n");
 309        out += sprintf(out, "-----------------------  current       min"
 310                       "       max   default  comment\n");
 311        out += sprintf(out, "brightness:             %8d  %8d  %8d  %8d\n",
 312                       cam->params.colourParams.brightness, 0, 100, 50);
 313        if (cam->params.version.firmwareVersion == 1 &&
 314           cam->params.version.firmwareRevision == 2)
 315                /* 1-02 firmware limits contrast to 80 */
 316                tmp = 80;
 317        else
 318                tmp = 96;
 319
 320        out += sprintf(out, "contrast:               %8d  %8d  %8d  %8d"
 321                       "  steps of 8\n",
 322                       cam->params.colourParams.contrast, 0, tmp, 48);
 323        out += sprintf(out, "saturation:             %8d  %8d  %8d  %8d\n",
 324                       cam->params.colourParams.saturation, 0, 100, 50);
 325        tmp = (25000+5000*cam->params.sensorFps.baserate)/
 326              (1<<cam->params.sensorFps.divisor);
 327        out += sprintf(out, "sensor_fps:             %4d.%03d  %8d  %8d  %8d\n",
 328                       tmp/1000, tmp%1000, 3, 30, 15);
 329        out += sprintf(out, "stream_start_line:      %8d  %8d  %8d  %8d\n",
 330                       2*cam->params.streamStartLine, 0,
 331                       cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
 332                       cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
 333        out += sprintf(out, "sub_sample:             %8s  %8s  %8s  %8s\n",
 334                       cam->params.format.subSample == SUBSAMPLE_420 ?
 335                       "420" : "422", "420", "422", "422");
 336        out += sprintf(out, "yuv_order:              %8s  %8s  %8s  %8s\n",
 337                       cam->params.format.yuvOrder == YUVORDER_YUYV ?
 338                       "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
 339        out += sprintf(out, "ecp_timing:             %8s  %8s  %8s  %8s\n",
 340                       cam->params.ecpTiming ? "slow" : "normal", "slow",
 341                       "normal", "normal");
 342
 343        if (cam->params.colourBalance.balanceMode == 2) {
 344                sprintf(tmpstr, "auto");
 345        } else {
 346                sprintf(tmpstr, "manual");
 347        }
 348        out += sprintf(out, "color_balance_mode:     %8s  %8s  %8s"
 349                       "  %8s\n",  tmpstr, "manual", "auto", "auto");
 350        out += sprintf(out, "red_gain:               %8d  %8d  %8d  %8d\n",
 351                       cam->params.colourBalance.redGain, 0, 212, 32);
 352        out += sprintf(out, "green_gain:             %8d  %8d  %8d  %8d\n",
 353                       cam->params.colourBalance.greenGain, 0, 212, 6);
 354        out += sprintf(out, "blue_gain:              %8d  %8d  %8d  %8d\n",
 355                       cam->params.colourBalance.blueGain, 0, 212, 92);
 356
 357        if (cam->params.version.firmwareVersion == 1 &&
 358           cam->params.version.firmwareRevision == 2)
 359                /* 1-02 firmware limits gain to 2 */
 360                sprintf(tmpstr, "%8d  %8d  %8d", 1, 2, 2);
 361        else
 362                sprintf(tmpstr, "%8d  %8d  %8d", 1, 8, 2);
 363
 364        if (cam->params.exposure.gainMode == 0)
 365                out += sprintf(out, "max_gain:                unknown  %28s"
 366                               "  powers of 2\n", tmpstr);
 367        else
 368                out += sprintf(out, "max_gain:               %8d  %28s"
 369                               "  1,2,4 or 8 \n",
 370                               1<<(cam->params.exposure.gainMode-1), tmpstr);
 371
 372        switch(cam->params.exposure.expMode) {
 373        case 1:
 374        case 3:
 375                sprintf(tmpstr, "manual");
 376                break;
 377        case 2:
 378                sprintf(tmpstr, "auto");
 379                break;
 380        default:
 381                sprintf(tmpstr, "unknown");
 382                break;
 383        }
 384        out += sprintf(out, "exposure_mode:          %8s  %8s  %8s"
 385                       "  %8s\n",  tmpstr, "manual", "auto", "auto");
 386        out += sprintf(out, "centre_weight:          %8s  %8s  %8s  %8s\n",
 387                       (2-cam->params.exposure.centreWeight) ? "on" : "off",
 388                       "off", "on", "on");
 389        out += sprintf(out, "gain:                   %8d  %8d  max_gain  %8d  1,2,4,8 possible\n",
 390                       1<<cam->params.exposure.gain, 1, 1);
 391        if (cam->params.version.firmwareVersion == 1 &&
 392           cam->params.version.firmwareRevision == 2)
 393                /* 1-02 firmware limits fineExp/2 to 127 */
 394                tmp = 254;
 395        else
 396                tmp = 510;
 397
 398        out += sprintf(out, "fine_exp:               %8d  %8d  %8d  %8d\n",
 399                       cam->params.exposure.fineExp*2, 0, tmp, 0);
 400        if (cam->params.version.firmwareVersion == 1 &&
 401           cam->params.version.firmwareRevision == 2)
 402                /* 1-02 firmware limits coarseExpHi to 0 */
 403                tmp = MAX_EXP_102;
 404        else
 405                tmp = MAX_EXP;
 406
 407        out += sprintf(out, "coarse_exp:             %8d  %8d  %8d"
 408                       "  %8d\n", cam->params.exposure.coarseExpLo+
 409                       256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
 410        out += sprintf(out, "red_comp:               %8d  %8d  %8d  %8d\n",
 411                       cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
 412        out += sprintf(out, "green1_comp:            %8d  %8d  %8d  %8d\n",
 413                       cam->params.exposure.green1Comp, COMP_GREEN1, 255,
 414                       COMP_GREEN1);
 415        out += sprintf(out, "green2_comp:            %8d  %8d  %8d  %8d\n",
 416                       cam->params.exposure.green2Comp, COMP_GREEN2, 255,
 417                       COMP_GREEN2);
 418        out += sprintf(out, "blue_comp:              %8d  %8d  %8d  %8d\n",
 419                       cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
 420
 421        out += sprintf(out, "apcor_gain1:            %#8x  %#8x  %#8x  %#8x\n",
 422                       cam->params.apcor.gain1, 0, 0xff, 0x1c);
 423        out += sprintf(out, "apcor_gain2:            %#8x  %#8x  %#8x  %#8x\n",
 424                       cam->params.apcor.gain2, 0, 0xff, 0x1a);
 425        out += sprintf(out, "apcor_gain4:            %#8x  %#8x  %#8x  %#8x\n",
 426                       cam->params.apcor.gain4, 0, 0xff, 0x2d);
 427        out += sprintf(out, "apcor_gain8:            %#8x  %#8x  %#8x  %#8x\n",
 428                       cam->params.apcor.gain8, 0, 0xff, 0x2a);
 429        out += sprintf(out, "vl_offset_gain1:        %8d  %8d  %8d  %8d\n",
 430                       cam->params.vlOffset.gain1, 0, 255, 24);
 431        out += sprintf(out, "vl_offset_gain2:        %8d  %8d  %8d  %8d\n",
 432                       cam->params.vlOffset.gain2, 0, 255, 28);
 433        out += sprintf(out, "vl_offset_gain4:        %8d  %8d  %8d  %8d\n",
 434                       cam->params.vlOffset.gain4, 0, 255, 30);
 435        out += sprintf(out, "vl_offset_gain8:        %8d  %8d  %8d  %8d\n",
 436                       cam->params.vlOffset.gain8, 0, 255, 30);
 437        out += sprintf(out, "flicker_control:        %8s  %8s  %8s  %8s\n",
 438                       cam->params.flickerControl.flickerMode ? "on" : "off",
 439                       "off", "on", "off");
 440        out += sprintf(out, "mains_frequency:        %8d  %8d  %8d  %8d"
 441                       " only 50/60\n",
 442                       cam->mainsFreq ? 60 : 50, 50, 60, 50);
 443        if(cam->params.flickerControl.allowableOverExposure < 0)
 444                out += sprintf(out, "allowable_overexposure: %4dauto      auto  %8d      auto\n",
 445                               -cam->params.flickerControl.allowableOverExposure,
 446                               255);
 447        else
 448                out += sprintf(out, "allowable_overexposure: %8d      auto  %8d      auto\n",
 449                               cam->params.flickerControl.allowableOverExposure,
 450                               255);
 451        out += sprintf(out, "compression_mode:       ");
 452        switch(cam->params.compression.mode) {
 453        case CPIA_COMPRESSION_NONE:
 454                out += sprintf(out, "%8s", "none");
 455                break;
 456        case CPIA_COMPRESSION_AUTO:
 457                out += sprintf(out, "%8s", "auto");
 458                break;
 459        case CPIA_COMPRESSION_MANUAL:
 460                out += sprintf(out, "%8s", "manual");
 461                break;
 462        default:
 463                out += sprintf(out, "%8s", "unknown");
 464                break;
 465        }
 466        out += sprintf(out, "    none,auto,manual      auto\n");
 467        out += sprintf(out, "decimation_enable:      %8s  %8s  %8s  %8s\n",
 468                       cam->params.compression.decimation ==
 469                       DECIMATION_ENAB ? "on":"off", "off", "on",
 470                       "off");
 471        out += sprintf(out, "compression_target:    %9s %9s %9s %9s\n",
 472                       cam->params.compressionTarget.frTargeting  ==
 473                       CPIA_COMPRESSION_TARGET_FRAMERATE ?
 474                       "framerate":"quality",
 475                       "framerate", "quality", "quality");
 476        out += sprintf(out, "target_framerate:       %8d  %8d  %8d  %8d\n",
 477                       cam->params.compressionTarget.targetFR, 1, 30, 15);
 478        out += sprintf(out, "target_quality:         %8d  %8d  %8d  %8d\n",
 479                       cam->params.compressionTarget.targetQ, 1, 64, 5);
 480        out += sprintf(out, "y_threshold:            %8d  %8d  %8d  %8d\n",
 481                       cam->params.yuvThreshold.yThreshold, 0, 31, 6);
 482        out += sprintf(out, "uv_threshold:           %8d  %8d  %8d  %8d\n",
 483                       cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
 484        out += sprintf(out, "hysteresis:             %8d  %8d  %8d  %8d\n",
 485                       cam->params.compressionParams.hysteresis, 0, 255, 3);
 486        out += sprintf(out, "threshold_max:          %8d  %8d  %8d  %8d\n",
 487                       cam->params.compressionParams.threshMax, 0, 255, 11);
 488        out += sprintf(out, "small_step:             %8d  %8d  %8d  %8d\n",
 489                       cam->params.compressionParams.smallStep, 0, 255, 1);
 490        out += sprintf(out, "large_step:             %8d  %8d  %8d  %8d\n",
 491                       cam->params.compressionParams.largeStep, 0, 255, 3);
 492        out += sprintf(out, "decimation_hysteresis:  %8d  %8d  %8d  %8d\n",
 493                       cam->params.compressionParams.decimationHysteresis,
 494                       0, 255, 2);
 495        out += sprintf(out, "fr_diff_step_thresh:    %8d  %8d  %8d  %8d\n",
 496                       cam->params.compressionParams.frDiffStepThresh,
 497                       0, 255, 5);
 498        out += sprintf(out, "q_diff_step_thresh:     %8d  %8d  %8d  %8d\n",
 499                       cam->params.compressionParams.qDiffStepThresh,
 500                       0, 255, 3);
 501        out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
 502                       cam->params.compressionParams.decimationThreshMod,
 503                       0, 255, 2);
 504        /* QX3 specific entries */
 505        if (cam->params.qx3.qx3_detected) {
 506                out += sprintf(out, "toplight:               %8s  %8s  %8s  %8s\n",
 507                               cam->params.qx3.toplight ? "on" : "off",
 508                               "off", "on", "off");
 509                out += sprintf(out, "bottomlight:            %8s  %8s  %8s  %8s\n",
 510                               cam->params.qx3.bottomlight ? "on" : "off",
 511                               "off", "on", "off");
 512        }
 513
 514        len = out - page;
 515        len -= off;
 516        if (len < count) {
 517                *eof = 1;
 518                if (len <= 0) return 0;
 519        } else
 520                len = count;
 521
 522        *start = page + off;
 523        return len;
 524}
 525
 526
 527static int match(char *checkstr, char **buffer, unsigned long *count,
 528                 int *find_colon, int *err)
 529{
 530        int ret, colon_found = 1;
 531        int len = strlen(checkstr);
 532        ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
 533        if (ret) {
 534                *buffer += len;
 535                *count -= len;
 536                if (*find_colon) {
 537                        colon_found = 0;
 538                        while (*count && (**buffer == ' ' || **buffer == '\t' ||
 539                                          (!colon_found && **buffer == ':'))) {
 540                                if (**buffer == ':')
 541                                        colon_found = 1;
 542                                --*count;
 543                                ++*buffer;
 544                        }
 545                        if (!*count || !colon_found)
 546                                *err = -EINVAL;
 547                        *find_colon = 0;
 548                }
 549        }
 550        return ret;
 551}
 552
 553static unsigned long int value(char **buffer, unsigned long *count, int *err)
 554{
 555        char *p;
 556        unsigned long int ret;
 557        ret = simple_strtoul(*buffer, &p, 0);
 558        if (p == *buffer)
 559                *err = -EINVAL;
 560        else {
 561                *count -= p - *buffer;
 562                *buffer = p;
 563        }
 564        return ret;
 565}
 566
 567static int cpia_write_proc(struct file *file, const char __user *buf,
 568                           unsigned long count, void *data)
 569{
 570        struct cam_data *cam = data;
 571        struct cam_params new_params;
 572        char *page, *buffer;
 573        int retval, find_colon;
 574        int size = count;
 575        unsigned long val = 0;
 576        u32 command_flags = 0;
 577        u8 new_mains;
 578
 579        /*
 580         * This code to copy from buf to page is shamelessly copied
 581         * from the comx driver
 582         */
 583        if (count > PAGE_SIZE) {
 584                printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
 585                return -ENOSPC;
 586        }
 587
 588        if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
 589
 590        if(copy_from_user(page, buf, count))
 591        {
 592                retval = -EFAULT;
 593                goto out;
 594        }
 595
 596        if (page[count-1] == '\n')
 597                page[count-1] = '\0';
 598        else if (count < PAGE_SIZE)
 599                page[count] = '\0';
 600        else if (page[count]) {
 601                retval = -EINVAL;
 602                goto out;
 603        }
 604
 605        buffer = page;
 606
 607        if (mutex_lock_interruptible(&cam->param_lock))
 608                return -ERESTARTSYS;
 609
 610        /*
 611         * Skip over leading whitespace
 612         */
 613        while (count && isspace(*buffer)) {
 614                --count;
 615                ++buffer;
 616        }
 617
 618        memcpy(&new_params, &cam->params, sizeof(struct cam_params));
 619        new_mains = cam->mainsFreq;
 620
 621#define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
 622#define VALUE (value(&buffer,&count, &retval))
 623#define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
 624                               new_params.version.firmwareRevision == (y))
 625
 626        retval = 0;
 627        while (count && !retval) {
 628                find_colon = 1;
 629                if (MATCH("brightness")) {
 630                        if (!retval)
 631                                val = VALUE;
 632
 633                        if (!retval) {
 634                                if (val <= 100)
 635                                        new_params.colourParams.brightness = val;
 636                                else
 637                                        retval = -EINVAL;
 638                        }
 639                        command_flags |= COMMAND_SETCOLOURPARAMS;
 640                        if(new_params.flickerControl.allowableOverExposure < 0)
 641                                new_params.flickerControl.allowableOverExposure =
 642                                        -find_over_exposure(new_params.colourParams.brightness);
 643                        if(new_params.flickerControl.flickerMode != 0)
 644                                command_flags |= COMMAND_SETFLICKERCTRL;
 645
 646                } else if (MATCH("contrast")) {
 647                        if (!retval)
 648                                val = VALUE;
 649
 650                        if (!retval) {
 651                                if (val <= 100) {
 652                                        /* contrast is in steps of 8, so round*/
 653                                        val = ((val + 3) / 8) * 8;
 654                                        /* 1-02 firmware limits contrast to 80*/
 655                                        if (FIRMWARE_VERSION(1,2) && val > 80)
 656                                                val = 80;
 657
 658                                        new_params.colourParams.contrast = val;
 659                                } else
 660                                        retval = -EINVAL;
 661                        }
 662                        command_flags |= COMMAND_SETCOLOURPARAMS;
 663                } else if (MATCH("saturation")) {
 664                        if (!retval)
 665                                val = VALUE;
 666
 667                        if (!retval) {
 668                                if (val <= 100)
 669                                        new_params.colourParams.saturation = val;
 670                                else
 671                                        retval = -EINVAL;
 672                        }
 673                        command_flags |= COMMAND_SETCOLOURPARAMS;
 674                } else if (MATCH("sensor_fps")) {
 675                        if (!retval)
 676                                val = VALUE;
 677
 678                        if (!retval) {
 679                                /* find values so that sensorFPS is minimized,
 680                                 * but >= val */
 681                                if (val > 30)
 682                                        retval = -EINVAL;
 683                                else if (val > 25) {
 684                                        new_params.sensorFps.divisor = 0;
 685                                        new_params.sensorFps.baserate = 1;
 686                                } else if (val > 15) {
 687                                        new_params.sensorFps.divisor = 0;
 688                                        new_params.sensorFps.baserate = 0;
 689                                } else if (val > 12) {
 690                                        new_params.sensorFps.divisor = 1;
 691                                        new_params.sensorFps.baserate = 1;
 692                                } else if (val > 7) {
 693                                        new_params.sensorFps.divisor = 1;
 694                                        new_params.sensorFps.baserate = 0;
 695                                } else if (val > 6) {
 696                                        new_params.sensorFps.divisor = 2;
 697                                        new_params.sensorFps.baserate = 1;
 698                                } else if (val > 3) {
 699                                        new_params.sensorFps.divisor = 2;
 700                                        new_params.sensorFps.baserate = 0;
 701                                } else {
 702                                        new_params.sensorFps.divisor = 3;
 703                                        /* Either base rate would work here */
 704                                        new_params.sensorFps.baserate = 1;
 705                                }
 706                                new_params.flickerControl.coarseJump =
 707                                        flicker_jumps[new_mains]
 708                                        [new_params.sensorFps.baserate]
 709                                        [new_params.sensorFps.divisor];
 710                                if (new_params.flickerControl.flickerMode)
 711                                        command_flags |= COMMAND_SETFLICKERCTRL;
 712                        }
 713                        command_flags |= COMMAND_SETSENSORFPS;
 714                        cam->exposure_status = EXPOSURE_NORMAL;
 715                } else if (MATCH("stream_start_line")) {
 716                        if (!retval)
 717                                val = VALUE;
 718
 719                        if (!retval) {
 720                                int max_line = 288;
 721
 722                                if (new_params.format.videoSize == VIDEOSIZE_QCIF)
 723                                        max_line = 144;
 724                                if (val <= max_line)
 725                                        new_params.streamStartLine = val/2;
 726                                else
 727                                        retval = -EINVAL;
 728                        }
 729                } else if (MATCH("sub_sample")) {
 730                        if (!retval && MATCH("420"))
 731                                new_params.format.subSample = SUBSAMPLE_420;
 732                        else if (!retval && MATCH("422"))
 733                                new_params.format.subSample = SUBSAMPLE_422;
 734                        else
 735                                retval = -EINVAL;
 736
 737                        command_flags |= COMMAND_SETFORMAT;
 738                } else if (MATCH("yuv_order")) {
 739                        if (!retval && MATCH("YUYV"))
 740                                new_params.format.yuvOrder = YUVORDER_YUYV;
 741                        else if (!retval && MATCH("UYVY"))
 742                                new_params.format.yuvOrder = YUVORDER_UYVY;
 743                        else
 744                                retval = -EINVAL;
 745
 746                        command_flags |= COMMAND_SETFORMAT;
 747                } else if (MATCH("ecp_timing")) {
 748                        if (!retval && MATCH("normal"))
 749                                new_params.ecpTiming = 0;
 750                        else if (!retval && MATCH("slow"))
 751                                new_params.ecpTiming = 1;
 752                        else
 753                                retval = -EINVAL;
 754
 755                        command_flags |= COMMAND_SETECPTIMING;
 756                } else if (MATCH("color_balance_mode")) {
 757                        if (!retval && MATCH("manual"))
 758                                new_params.colourBalance.balanceMode = 3;
 759                        else if (!retval && MATCH("auto"))
 760                                new_params.colourBalance.balanceMode = 2;
 761                        else
 762                                retval = -EINVAL;
 763
 764                        command_flags |= COMMAND_SETCOLOURBALANCE;
 765                } else if (MATCH("red_gain")) {
 766                        if (!retval)
 767                                val = VALUE;
 768
 769                        if (!retval) {
 770                                if (val <= 212) {
 771                                        new_params.colourBalance.redGain = val;
 772                                        new_params.colourBalance.balanceMode = 1;
 773                                } else
 774                                        retval = -EINVAL;
 775                        }
 776                        command_flags |= COMMAND_SETCOLOURBALANCE;
 777                } else if (MATCH("green_gain")) {
 778                        if (!retval)
 779                                val = VALUE;
 780
 781                        if (!retval) {
 782                                if (val <= 212) {
 783                                        new_params.colourBalance.greenGain = val;
 784                                        new_params.colourBalance.balanceMode = 1;
 785                                } else
 786                                        retval = -EINVAL;
 787                        }
 788                        command_flags |= COMMAND_SETCOLOURBALANCE;
 789                } else if (MATCH("blue_gain")) {
 790                        if (!retval)
 791                                val = VALUE;
 792
 793                        if (!retval) {
 794                                if (val <= 212) {
 795                                        new_params.colourBalance.blueGain = val;
 796                                        new_params.colourBalance.balanceMode = 1;
 797                                } else
 798                                        retval = -EINVAL;
 799                        }
 800                        command_flags |= COMMAND_SETCOLOURBALANCE;
 801                } else if (MATCH("max_gain")) {
 802                        if (!retval)
 803                                val = VALUE;
 804
 805                        if (!retval) {
 806                                /* 1-02 firmware limits gain to 2 */
 807                                if (FIRMWARE_VERSION(1,2) && val > 2)
 808                                        val = 2;
 809                                switch(val) {
 810                                case 1:
 811                                        new_params.exposure.gainMode = 1;
 812                                        break;
 813                                case 2:
 814                                        new_params.exposure.gainMode = 2;
 815                                        break;
 816                                case 4:
 817                                        new_params.exposure.gainMode = 3;
 818                                        break;
 819                                case 8:
 820                                        new_params.exposure.gainMode = 4;
 821                                        break;
 822                                default:
 823                                        retval = -EINVAL;
 824                                        break;
 825                                }
 826                        }
 827                        command_flags |= COMMAND_SETEXPOSURE;
 828                } else if (MATCH("exposure_mode")) {
 829                        if (!retval && MATCH("auto"))
 830                                new_params.exposure.expMode = 2;
 831                        else if (!retval && MATCH("manual")) {
 832                                if (new_params.exposure.expMode == 2)
 833                                        new_params.exposure.expMode = 3;
 834                                if(new_params.flickerControl.flickerMode != 0)
 835                                        command_flags |= COMMAND_SETFLICKERCTRL;
 836                                new_params.flickerControl.flickerMode = 0;
 837                        } else
 838                                retval = -EINVAL;
 839
 840                        command_flags |= COMMAND_SETEXPOSURE;
 841                } else if (MATCH("centre_weight")) {
 842                        if (!retval && MATCH("on"))
 843                                new_params.exposure.centreWeight = 1;
 844                        else if (!retval && MATCH("off"))
 845                                new_params.exposure.centreWeight = 2;
 846                        else
 847                                retval = -EINVAL;
 848
 849                        command_flags |= COMMAND_SETEXPOSURE;
 850                } else if (MATCH("gain")) {
 851                        if (!retval)
 852                                val = VALUE;
 853
 854                        if (!retval) {
 855                                switch(val) {
 856                                case 1:
 857                                        new_params.exposure.gain = 0;
 858                                        break;
 859                                case 2:
 860                                        new_params.exposure.gain = 1;
 861                                        break;
 862                                case 4:
 863                                        new_params.exposure.gain = 2;
 864                                        break;
 865                                case 8:
 866                                        new_params.exposure.gain = 3;
 867                                        break;
 868                                default:
 869                                        retval = -EINVAL;
 870                                        break;
 871                                }
 872                                new_params.exposure.expMode = 1;
 873                                if(new_params.flickerControl.flickerMode != 0)
 874                                        command_flags |= COMMAND_SETFLICKERCTRL;
 875                                new_params.flickerControl.flickerMode = 0;
 876                                command_flags |= COMMAND_SETEXPOSURE;
 877                                if (new_params.exposure.gain >
 878                                    new_params.exposure.gainMode-1)
 879                                        retval = -EINVAL;
 880                        }
 881                } else if (MATCH("fine_exp")) {
 882                        if (!retval)
 883                                val = VALUE/2;
 884
 885                        if (!retval) {
 886                                if (val < 256) {
 887                                        /* 1-02 firmware limits fineExp/2 to 127*/
 888                                        if (FIRMWARE_VERSION(1,2) && val > 127)
 889                                                val = 127;
 890                                        new_params.exposure.fineExp = val;
 891                                        new_params.exposure.expMode = 1;
 892                                        command_flags |= COMMAND_SETEXPOSURE;
 893                                        if(new_params.flickerControl.flickerMode != 0)
 894                                                command_flags |= COMMAND_SETFLICKERCTRL;
 895                                        new_params.flickerControl.flickerMode = 0;
 896                                        command_flags |= COMMAND_SETFLICKERCTRL;
 897                                } else
 898                                        retval = -EINVAL;
 899                        }
 900                } else if (MATCH("coarse_exp")) {
 901                        if (!retval)
 902                                val = VALUE;
 903
 904                        if (!retval) {
 905                                if (val <= MAX_EXP) {
 906                                        if (FIRMWARE_VERSION(1,2) &&
 907                                            val > MAX_EXP_102)
 908                                                val = MAX_EXP_102;
 909                                        new_params.exposure.coarseExpLo =
 910                                                val & 0xff;
 911                                        new_params.exposure.coarseExpHi =
 912                                                val >> 8;
 913                                        new_params.exposure.expMode = 1;
 914                                        command_flags |= COMMAND_SETEXPOSURE;
 915                                        if(new_params.flickerControl.flickerMode != 0)
 916                                                command_flags |= COMMAND_SETFLICKERCTRL;
 917                                        new_params.flickerControl.flickerMode = 0;
 918                                        command_flags |= COMMAND_SETFLICKERCTRL;
 919                                } else
 920                                        retval = -EINVAL;
 921                        }
 922                } else if (MATCH("red_comp")) {
 923                        if (!retval)
 924                                val = VALUE;
 925
 926                        if (!retval) {
 927                                if (val >= COMP_RED && val <= 255) {
 928                                        new_params.exposure.redComp = val;
 929                                        new_params.exposure.compMode = 1;
 930                                        command_flags |= COMMAND_SETEXPOSURE;
 931                                } else
 932                                        retval = -EINVAL;
 933                        }
 934                } else if (MATCH("green1_comp")) {
 935                        if (!retval)
 936                                val = VALUE;
 937
 938                        if (!retval) {
 939                                if (val >= COMP_GREEN1 && val <= 255) {
 940                                        new_params.exposure.green1Comp = val;
 941                                        new_params.exposure.compMode = 1;
 942                                        command_flags |= COMMAND_SETEXPOSURE;
 943                                } else
 944                                        retval = -EINVAL;
 945                        }
 946                } else if (MATCH("green2_comp")) {
 947                        if (!retval)
 948                                val = VALUE;
 949
 950                        if (!retval) {
 951                                if (val >= COMP_GREEN2 && val <= 255) {
 952                                        new_params.exposure.green2Comp = val;
 953                                        new_params.exposure.compMode = 1;
 954                                        command_flags |= COMMAND_SETEXPOSURE;
 955                                } else
 956                                        retval = -EINVAL;
 957                        }
 958                } else if (MATCH("blue_comp")) {
 959                        if (!retval)
 960                                val = VALUE;
 961
 962                        if (!retval) {
 963                                if (val >= COMP_BLUE && val <= 255) {
 964                                        new_params.exposure.blueComp = val;
 965                                        new_params.exposure.compMode = 1;
 966                                        command_flags |= COMMAND_SETEXPOSURE;
 967                                } else
 968                                        retval = -EINVAL;
 969                        }
 970                } else if (MATCH("apcor_gain1")) {
 971                        if (!retval)
 972                                val = VALUE;
 973
 974                        if (!retval) {
 975                                command_flags |= COMMAND_SETAPCOR;
 976                                if (val <= 0xff)
 977                                        new_params.apcor.gain1 = val;
 978                                else
 979                                        retval = -EINVAL;
 980                        }
 981                } else if (MATCH("apcor_gain2")) {
 982                        if (!retval)
 983                                val = VALUE;
 984
 985                        if (!retval) {
 986                                command_flags |= COMMAND_SETAPCOR;
 987                                if (val <= 0xff)
 988                                        new_params.apcor.gain2 = val;
 989                                else
 990                                        retval = -EINVAL;
 991                        }
 992                } else if (MATCH("apcor_gain4")) {
 993                        if (!retval)
 994                                val = VALUE;
 995
 996                        if (!retval) {
 997                                command_flags |= COMMAND_SETAPCOR;
 998                                if (val <= 0xff)
 999                                        new_params.apcor.gain4 = val;
1000                                else
1001                                        retval = -EINVAL;
1002                        }
1003                } else if (MATCH("apcor_gain8")) {
1004                        if (!retval)
1005                                val = VALUE;
1006
1007                        if (!retval) {
1008                                command_flags |= COMMAND_SETAPCOR;
1009                                if (val <= 0xff)
1010                                        new_params.apcor.gain8 = val;
1011                                else
1012                                        retval = -EINVAL;
1013                        }
1014                } else if (MATCH("vl_offset_gain1")) {
1015                        if (!retval)
1016                                val = VALUE;
1017
1018                        if (!retval) {
1019                                if (val <= 0xff)
1020                                        new_params.vlOffset.gain1 = val;
1021                                else
1022                                        retval = -EINVAL;
1023                        }
1024                        command_flags |= COMMAND_SETVLOFFSET;
1025                } else if (MATCH("vl_offset_gain2")) {
1026                        if (!retval)
1027                                val = VALUE;
1028
1029                        if (!retval) {
1030                                if (val <= 0xff)
1031                                        new_params.vlOffset.gain2 = val;
1032                                else
1033                                        retval = -EINVAL;
1034                        }
1035                        command_flags |= COMMAND_SETVLOFFSET;
1036                } else if (MATCH("vl_offset_gain4")) {
1037                        if (!retval)
1038                                val = VALUE;
1039
1040                        if (!retval) {
1041                                if (val <= 0xff)
1042                                        new_params.vlOffset.gain4 = val;
1043                                else
1044                                        retval = -EINVAL;
1045                        }
1046                        command_flags |= COMMAND_SETVLOFFSET;
1047                } else if (MATCH("vl_offset_gain8")) {
1048                        if (!retval)
1049                                val = VALUE;
1050
1051                        if (!retval) {
1052                                if (val <= 0xff)
1053                                        new_params.vlOffset.gain8 = val;
1054                                else
1055                                        retval = -EINVAL;
1056                        }
1057                        command_flags |= COMMAND_SETVLOFFSET;
1058                } else if (MATCH("flicker_control")) {
1059                        if (!retval && MATCH("on")) {
1060                                set_flicker(&new_params, &command_flags, 1);
1061                        } else if (!retval && MATCH("off")) {
1062                                set_flicker(&new_params, &command_flags, 0);
1063                        } else
1064                                retval = -EINVAL;
1065
1066                        command_flags |= COMMAND_SETFLICKERCTRL;
1067                } else if (MATCH("mains_frequency")) {
1068                        if (!retval && MATCH("50")) {
1069                                new_mains = 0;
1070                                new_params.flickerControl.coarseJump =
1071                                        flicker_jumps[new_mains]
1072                                        [new_params.sensorFps.baserate]
1073                                        [new_params.sensorFps.divisor];
1074                                if (new_params.flickerControl.flickerMode)
1075                                        command_flags |= COMMAND_SETFLICKERCTRL;
1076                        } else if (!retval && MATCH("60")) {
1077                                new_mains = 1;
1078                                new_params.flickerControl.coarseJump =
1079                                        flicker_jumps[new_mains]
1080                                        [new_params.sensorFps.baserate]
1081                                        [new_params.sensorFps.divisor];
1082                                if (new_params.flickerControl.flickerMode)
1083                                        command_flags |= COMMAND_SETFLICKERCTRL;
1084                        } else
1085                                retval = -EINVAL;
1086                } else if (MATCH("allowable_overexposure")) {
1087                        if (!retval && MATCH("auto")) {
1088                                new_params.flickerControl.allowableOverExposure =
1089                                        -find_over_exposure(new_params.colourParams.brightness);
1090                                if(new_params.flickerControl.flickerMode != 0)
1091                                        command_flags |= COMMAND_SETFLICKERCTRL;
1092                        } else {
1093                                if (!retval)
1094                                        val = VALUE;
1095
1096                                if (!retval) {
1097                                        if (val <= 0xff) {
1098                                                new_params.flickerControl.
1099                                                        allowableOverExposure = val;
1100                                                if(new_params.flickerControl.flickerMode != 0)
1101                                                        command_flags |= COMMAND_SETFLICKERCTRL;
1102                                        } else
1103                                                retval = -EINVAL;
1104                                }
1105                        }
1106                } else if (MATCH("compression_mode")) {
1107                        if (!retval && MATCH("none"))
1108                                new_params.compression.mode =
1109                                        CPIA_COMPRESSION_NONE;
1110                        else if (!retval && MATCH("auto"))
1111                                new_params.compression.mode =
1112                                        CPIA_COMPRESSION_AUTO;
1113                        else if (!retval && MATCH("manual"))
1114                                new_params.compression.mode =
1115                                        CPIA_COMPRESSION_MANUAL;
1116                        else
1117                                retval = -EINVAL;
1118
1119                        command_flags |= COMMAND_SETCOMPRESSION;
1120                } else if (MATCH("decimation_enable")) {
1121                        if (!retval && MATCH("off"))
1122                                new_params.compression.decimation = 0;
1123                        else if (!retval && MATCH("on"))
1124                                new_params.compression.decimation = 1;
1125                        else
1126                                retval = -EINVAL;
1127
1128                        command_flags |= COMMAND_SETCOMPRESSION;
1129                } else if (MATCH("compression_target")) {
1130                        if (!retval && MATCH("quality"))
1131                                new_params.compressionTarget.frTargeting =
1132                                        CPIA_COMPRESSION_TARGET_QUALITY;
1133                        else if (!retval && MATCH("framerate"))
1134                                new_params.compressionTarget.frTargeting =
1135                                        CPIA_COMPRESSION_TARGET_FRAMERATE;
1136                        else
1137                                retval = -EINVAL;
1138
1139                        command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1140                } else if (MATCH("target_framerate")) {
1141                        if (!retval)
1142                                val = VALUE;
1143
1144                        if (!retval) {
1145                                if(val > 0 && val <= 30)
1146                                        new_params.compressionTarget.targetFR = val;
1147                                else
1148                                        retval = -EINVAL;
1149                        }
1150                        command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1151                } else if (MATCH("target_quality")) {
1152                        if (!retval)
1153                                val = VALUE;
1154
1155                        if (!retval) {
1156                                if(val > 0 && val <= 64)
1157                                        new_params.compressionTarget.targetQ = val;
1158                                else
1159                                        retval = -EINVAL;
1160                        }
1161                        command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1162                } else if (MATCH("y_threshold")) {
1163                        if (!retval)
1164                                val = VALUE;
1165
1166                        if (!retval) {
1167                                if (val < 32)
1168                                        new_params.yuvThreshold.yThreshold = val;
1169                                else
1170                                        retval = -EINVAL;
1171                        }
1172                        command_flags |= COMMAND_SETYUVTHRESH;
1173                } else if (MATCH("uv_threshold")) {
1174                        if (!retval)
1175                                val = VALUE;
1176
1177                        if (!retval) {
1178                                if (val < 32)
1179                                        new_params.yuvThreshold.uvThreshold = val;
1180                                else
1181                                        retval = -EINVAL;
1182                        }
1183                        command_flags |= COMMAND_SETYUVTHRESH;
1184                } else if (MATCH("hysteresis")) {
1185                        if (!retval)
1186                                val = VALUE;
1187
1188                        if (!retval) {
1189                                if (val <= 0xff)
1190                                        new_params.compressionParams.hysteresis = val;
1191                                else
1192                                        retval = -EINVAL;
1193                        }
1194                        command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1195                } else if (MATCH("threshold_max")) {
1196                        if (!retval)
1197                                val = VALUE;
1198
1199                        if (!retval) {
1200                                if (val <= 0xff)
1201                                        new_params.compressionParams.threshMax = val;
1202                                else
1203                                        retval = -EINVAL;
1204                        }
1205                        command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1206                } else if (MATCH("small_step")) {
1207                        if (!retval)
1208                                val = VALUE;
1209
1210                        if (!retval) {
1211                                if (val <= 0xff)
1212                                        new_params.compressionParams.smallStep = val;
1213                                else
1214                                        retval = -EINVAL;
1215                        }
1216                        command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1217                } else if (MATCH("large_step")) {
1218                        if (!retval)
1219                                val = VALUE;
1220
1221                        if (!retval) {
1222                                if (val <= 0xff)
1223                                        new_params.compressionParams.largeStep = val;
1224                                else
1225                                        retval = -EINVAL;
1226                        }
1227                        command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1228                } else if (MATCH("decimation_hysteresis")) {
1229                        if (!retval)
1230                                val = VALUE;
1231
1232                        if (!retval) {
1233                                if (val <= 0xff)
1234                                        new_params.compressionParams.decimationHysteresis = val;
1235                                else
1236                                        retval = -EINVAL;
1237                        }
1238                        command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1239                } else if (MATCH("fr_diff_step_thresh")) {
1240                        if (!retval)
1241                                val = VALUE;
1242
1243                        if (!retval) {
1244                                if (val <= 0xff)
1245                                        new_params.compressionParams.frDiffStepThresh = val;
1246                                else
1247                                        retval = -EINVAL;
1248                        }
1249                        command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1250                } else if (MATCH("q_diff_step_thresh")) {
1251                        if (!retval)
1252                                val = VALUE;
1253
1254                        if (!retval) {
1255                                if (val <= 0xff)
1256                                        new_params.compressionParams.qDiffStepThresh = val;
1257                                else
1258                                        retval = -EINVAL;
1259                        }
1260                        command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1261                } else if (MATCH("decimation_thresh_mod")) {
1262                        if (!retval)
1263                                val = VALUE;
1264
1265                        if (!retval) {
1266                                if (val <= 0xff)
1267                                        new_params.compressionParams.decimationThreshMod = val;
1268                                else
1269                                        retval = -EINVAL;
1270                        }
1271                        command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1272                } else if (MATCH("toplight")) {
1273                        if (!retval && MATCH("on"))
1274                                new_params.qx3.toplight = 1;
1275                        else if (!retval && MATCH("off"))
1276                                new_params.qx3.toplight = 0;
1277                        else
1278                                retval = -EINVAL;
1279                        command_flags |= COMMAND_SETLIGHTS;
1280                } else if (MATCH("bottomlight")) {
1281                        if (!retval && MATCH("on"))
1282                                new_params.qx3.bottomlight = 1;
1283                        else if (!retval && MATCH("off"))
1284                                new_params.qx3.bottomlight = 0;
1285                        else
1286                                retval = -EINVAL;
1287                        command_flags |= COMMAND_SETLIGHTS;
1288                } else {
1289                        DBG("No match found\n");
1290                        retval = -EINVAL;
1291                }
1292
1293                if (!retval) {
1294                        while (count && isspace(*buffer) && *buffer != '\n') {
1295                                --count;
1296                                ++buffer;
1297                        }
1298                        if (count) {
1299                                if (*buffer == '\0' && count != 1)
1300                                        retval = -EINVAL;
1301                                else if (*buffer != '\n' && *buffer != ';' &&
1302                                         *buffer != '\0')
1303                                        retval = -EINVAL;
1304                                else {
1305                                        --count;
1306                                        ++buffer;
1307                                }
1308                        }
1309                }
1310        }
1311#undef MATCH
1312#undef VALUE
1313#undef FIRMWARE_VERSION
1314        if (!retval) {
1315                if (command_flags & COMMAND_SETCOLOURPARAMS) {
1316                        /* Adjust cam->vp to reflect these changes */
1317                        cam->vp.brightness =
1318                                new_params.colourParams.brightness*65535/100;
1319                        cam->vp.contrast =
1320                                new_params.colourParams.contrast*65535/100;
1321                        cam->vp.colour =
1322                                new_params.colourParams.saturation*65535/100;
1323                }
1324                if((command_flags & COMMAND_SETEXPOSURE) &&
1325                   new_params.exposure.expMode == 2)
1326                        cam->exposure_status = EXPOSURE_NORMAL;
1327
1328                memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1329                cam->mainsFreq = new_mains;
1330                cam->cmd_queue |= command_flags;
1331                retval = size;
1332        } else
1333                DBG("error: %d\n", retval);
1334
1335        mutex_unlock(&cam->param_lock);
1336
1337out:
1338        free_page((unsigned long)page);
1339        return retval;
1340}
1341
1342static void create_proc_cpia_cam(struct cam_data *cam)
1343{
1344        char name[5 + 1 + 10 + 1];
1345        struct proc_dir_entry *ent;
1346
1347        if (!cpia_proc_root || !cam)
1348                return;
1349
1350        snprintf(name, sizeof(name), "video%d", cam->vdev.num);
1351
1352        ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1353        if (!ent)
1354                return;
1355
1356        ent->data = cam;
1357        ent->read_proc = cpia_read_proc;
1358        ent->write_proc = cpia_write_proc;
1359        /*
1360           size of the proc entry is 3736 bytes for the standard webcam;
1361           the extra features of the QX3 microscope add 189 bytes.
1362           (we have not yet probed the camera to see which type it is).
1363        */
1364        ent->size = 3736 + 189;
1365        cam->proc_entry = ent;
1366}
1367
1368static void destroy_proc_cpia_cam(struct cam_data *cam)
1369{
1370        char name[5 + 1 + 10 + 1];
1371
1372        if (!cam || !cam->proc_entry)
1373                return;
1374
1375        snprintf(name, sizeof(name), "video%d", cam->vdev.num);
1376        remove_proc_entry(name, cpia_proc_root);
1377        cam->proc_entry = NULL;
1378}
1379
1380static void proc_cpia_create(void)
1381{
1382        cpia_proc_root = proc_mkdir("cpia", NULL);
1383
1384        if (cpia_proc_root)
1385                cpia_proc_root->owner = THIS_MODULE;
1386        else
1387                LOG("Unable to initialise /proc/cpia\n");
1388}
1389
1390static void __exit proc_cpia_destroy(void)
1391{
1392        remove_proc_entry("cpia", NULL);
1393}
1394#endif /* CONFIG_PROC_FS */
1395
1396/* ----------------------- debug functions ---------------------- */
1397
1398#define printstatus(cam) \
1399  DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1400        cam->params.status.systemState, cam->params.status.grabState, \
1401        cam->params.status.streamState, cam->params.status.fatalError, \
1402        cam->params.status.cmdError, cam->params.status.debugFlags, \
1403        cam->params.status.vpStatus, cam->params.status.errorCode);
1404
1405/* ----------------------- v4l helpers -------------------------- */
1406
1407/* supported frame palettes and depths */
1408static inline int valid_mode(u16 palette, u16 depth)
1409{
1410        if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1411            (palette == VIDEO_PALETTE_YUYV && depth == 16))
1412                return 1;
1413
1414        if (colorspace_conv)
1415                return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1416                       (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1417                       (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1418                       (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1419                       (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1420                       (palette == VIDEO_PALETTE_UYVY && depth == 16);
1421
1422        return 0;
1423}
1424
1425static int match_videosize( int width, int height )
1426{
1427        /* return the best match, where 'best' is as always
1428         * the largest that is not bigger than what is requested. */
1429        if (width>=352 && height>=288)
1430                return VIDEOSIZE_352_288; /* CIF */
1431
1432        if (width>=320 && height>=240)
1433                return VIDEOSIZE_320_240; /* SIF */
1434
1435        if (width>=288 && height>=216)
1436                return VIDEOSIZE_288_216;
1437
1438        if (width>=256 && height>=192)
1439                return VIDEOSIZE_256_192;
1440
1441        if (width>=224 && height>=168)
1442                return VIDEOSIZE_224_168;
1443
1444        if (width>=192 && height>=144)
1445                return VIDEOSIZE_192_144;
1446
1447        if (width>=176 && height>=144)
1448                return VIDEOSIZE_176_144; /* QCIF */
1449
1450        if (width>=160 && height>=120)
1451                return VIDEOSIZE_160_120; /* QSIF */
1452
1453        if (width>=128 && height>=96)
1454                return VIDEOSIZE_128_96;
1455
1456        if (width>=88 && height>=72)
1457                return VIDEOSIZE_88_72;
1458
1459        if (width>=64 && height>=48)
1460                return VIDEOSIZE_64_48;
1461
1462        if (width>=48 && height>=48)
1463                return VIDEOSIZE_48_48;
1464
1465        return -1;
1466}
1467
1468/* these are the capture sizes we support */
1469static void set_vw_size(struct cam_data *cam)
1470{
1471        /* the col/row/start/end values are the result of simple math    */
1472        /* study the SetROI-command in cpia developers guide p 2-22      */
1473        /* streamStartLine is set to the recommended value in the cpia   */
1474        /*  developers guide p 3-37                                      */
1475        switch(cam->video_size) {
1476        case VIDEOSIZE_CIF:
1477                cam->vw.width = 352;
1478                cam->vw.height = 288;
1479                cam->params.format.videoSize=VIDEOSIZE_CIF;
1480                cam->params.roi.colStart=0;
1481                cam->params.roi.rowStart=0;
1482                cam->params.streamStartLine = 120;
1483                break;
1484        case VIDEOSIZE_SIF:
1485                cam->vw.width = 320;
1486                cam->vw.height = 240;
1487                cam->params.format.videoSize=VIDEOSIZE_CIF;
1488                cam->params.roi.colStart=2;
1489                cam->params.roi.rowStart=6;
1490                cam->params.streamStartLine = 120;
1491                break;
1492        case VIDEOSIZE_288_216:
1493                cam->vw.width = 288;
1494                cam->vw.height = 216;
1495                cam->params.format.videoSize=VIDEOSIZE_CIF;
1496                cam->params.roi.colStart=4;
1497                cam->params.roi.rowStart=9;
1498                cam->params.streamStartLine = 120;
1499                break;
1500        case VIDEOSIZE_256_192:
1501                cam->vw.width = 256;
1502                cam->vw.height = 192;
1503                cam->params.format.videoSize=VIDEOSIZE_CIF;
1504                cam->params.roi.colStart=6;
1505                cam->params.roi.rowStart=12;
1506                cam->params.streamStartLine = 120;
1507                break;
1508        case VIDEOSIZE_224_168:
1509                cam->vw.width = 224;
1510                cam->vw.height = 168;
1511                cam->params.format.videoSize=VIDEOSIZE_CIF;
1512                cam->params.roi.colStart=8;
1513                cam->params.roi.rowStart=15;
1514                cam->params.streamStartLine = 120;
1515                break;
1516        case VIDEOSIZE_192_144:
1517                cam->vw.width = 192;
1518                cam->vw.height = 144;
1519                cam->params.format.videoSize=VIDEOSIZE_CIF;
1520                cam->params.roi.colStart=10;
1521                cam->params.roi.rowStart=18;
1522                cam->params.streamStartLine = 120;
1523                break;
1524        case VIDEOSIZE_QCIF:
1525                cam->vw.width = 176;
1526                cam->vw.height = 144;
1527                cam->params.format.videoSize=VIDEOSIZE_QCIF;
1528                cam->params.roi.colStart=0;
1529                cam->params.roi.rowStart=0;
1530                cam->params.streamStartLine = 60;
1531                break;
1532        case VIDEOSIZE_QSIF:
1533                cam->vw.width = 160;
1534                cam->vw.height = 120;
1535                cam->params.format.videoSize=VIDEOSIZE_QCIF;
1536                cam->params.roi.colStart=1;
1537                cam->params.roi.rowStart=3;
1538                cam->params.streamStartLine = 60;
1539                break;
1540        case VIDEOSIZE_128_96:
1541                cam->vw.width = 128;
1542                cam->vw.height = 96;
1543                cam->params.format.videoSize=VIDEOSIZE_QCIF;
1544                cam->params.roi.colStart=3;
1545                cam->params.roi.rowStart=6;
1546                cam->params.streamStartLine = 60;
1547                break;
1548        case VIDEOSIZE_88_72:
1549                cam->vw.width = 88;
1550                cam->vw.height = 72;
1551                cam->params.format.videoSize=VIDEOSIZE_QCIF;
1552                cam->params.roi.colStart=5;
1553                cam->params.roi.rowStart=9;
1554                cam->params.streamStartLine = 60;
1555                break;
1556        case VIDEOSIZE_64_48:
1557                cam->vw.width = 64;
1558                cam->vw.height = 48;
1559                cam->params.format.videoSize=VIDEOSIZE_QCIF;
1560                cam->params.roi.colStart=7;
1561                cam->params.roi.rowStart=12;
1562                cam->params.streamStartLine = 60;
1563                break;
1564        case VIDEOSIZE_48_48:
1565                cam->vw.width = 48;
1566                cam->vw.height = 48;
1567                cam->params.format.videoSize=VIDEOSIZE_QCIF;
1568                cam->params.roi.colStart=8;
1569                cam->params.roi.rowStart=6;
1570                cam->params.streamStartLine = 60;
1571                break;
1572        default:
1573                LOG("bad videosize value: %d\n", cam->video_size);
1574                return;
1575        }
1576
1577        if(cam->vc.width == 0)
1578                cam->vc.width = cam->vw.width;
1579        if(cam->vc.height == 0)
1580                cam->vc.height = cam->vw.height;
1581
1582        cam->params.roi.colStart += cam->vc.x >> 3;
1583        cam->params.roi.colEnd = cam->params.roi.colStart +
1584                                 (cam->vc.width >> 3);
1585        cam->params.roi.rowStart += cam->vc.y >> 2;
1586        cam->params.roi.rowEnd = cam->params.roi.rowStart +
1587                                 (cam->vc.height >> 2);
1588
1589        return;
1590}
1591
1592static int allocate_frame_buf(struct cam_data *cam)
1593{
1594        int i;
1595
1596        cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1597        if (!cam->frame_buf)
1598                return -ENOBUFS;
1599
1600        for (i = 0; i < FRAME_NUM; i++)
1601                cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1602
1603        return 0;
1604}
1605
1606static int free_frame_buf(struct cam_data *cam)
1607{
1608        int i;
1609
1610        rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1611        cam->frame_buf = NULL;
1612        for (i=0; i < FRAME_NUM; i++)
1613                cam->frame[i].data = NULL;
1614
1615        return 0;
1616}
1617
1618
1619static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
1620{
1621        int i;
1622
1623        for (i=0; i < FRAME_NUM; i++)
1624                frame[i].state = FRAME_UNUSED;
1625        return;
1626}
1627
1628/**********************************************************************
1629 *
1630 * General functions
1631 *
1632 **********************************************************************/
1633/* send an arbitrary command to the camera */
1634static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1635{
1636        int retval, datasize;
1637        u8 cmd[8], data[8];
1638
1639        switch(command) {
1640        case CPIA_COMMAND_GetCPIAVersion:
1641        case CPIA_COMMAND_GetPnPID:
1642        case CPIA_COMMAND_GetCameraStatus:
1643        case CPIA_COMMAND_GetVPVersion:
1644                datasize=8;
1645                break;
1646        case CPIA_COMMAND_GetColourParams:
1647        case CPIA_COMMAND_GetColourBalance:
1648        case CPIA_COMMAND_GetExposure:
1649                mutex_lock(&cam->param_lock);
1650                datasize=8;
1651                break;
1652        case CPIA_COMMAND_ReadMCPorts:
1653        case CPIA_COMMAND_ReadVCRegs:
1654                datasize = 4;
1655                break;
1656        default:
1657                datasize=0;
1658                break;
1659        }
1660
1661        cmd[0] = command>>8;
1662        cmd[1] = command&0xff;
1663        cmd[2] = a;
1664        cmd[3] = b;
1665        cmd[4] = c;
1666        cmd[5] = d;
1667        cmd[6] = datasize;
1668        cmd[7] = 0;
1669
1670        retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1671        if (retval) {
1672                DBG("%x - failed, retval=%d\n", command, retval);
1673                if (command == CPIA_COMMAND_GetColourParams ||
1674                    command == CPIA_COMMAND_GetColourBalance ||
1675                    command == CPIA_COMMAND_GetExposure)
1676                        mutex_unlock(&cam->param_lock);
1677        } else {
1678                switch(command) {
1679                case CPIA_COMMAND_GetCPIAVersion:
1680                        cam->params.version.firmwareVersion = data[0];
1681                        cam->params.version.firmwareRevision = data[1];
1682                        cam->params.version.vcVersion = data[2];
1683                        cam->params.version.vcRevision = data[3];
1684                        break;
1685                case CPIA_COMMAND_GetPnPID:
1686                        cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1687                        cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1688                        cam->params.pnpID.deviceRevision =
1689                                data[4]+(((u16)data[5])<<8);
1690                        break;
1691                case CPIA_COMMAND_GetCameraStatus:
1692                        cam->params.status.systemState = data[0];
1693                        cam->params.status.grabState = data[1];
1694                        cam->params.status.streamState = data[2];
1695                        cam->params.status.fatalError = data[3];
1696                        cam->params.status.cmdError = data[4];
1697                        cam->params.status.debugFlags = data[5];
1698                        cam->params.status.vpStatus = data[6];
1699                        cam->params.status.errorCode = data[7];
1700                        break;
1701                case CPIA_COMMAND_GetVPVersion:
1702                        cam->params.vpVersion.vpVersion = data[0];
1703                        cam->params.vpVersion.vpRevision = data[1];
1704                        cam->params.vpVersion.cameraHeadID =
1705                                data[2]+(((u16)data[3])<<8);
1706                        break;
1707                case CPIA_COMMAND_GetColourParams:
1708                        cam->params.colourParams.brightness = data[0];
1709                        cam->params.colourParams.contrast = data[1];
1710                        cam->params.colourParams.saturation = data[2];
1711                        mutex_unlock(&cam->param_lock);
1712                        break;
1713                case CPIA_COMMAND_GetColourBalance:
1714                        cam->params.colourBalance.redGain = data[0];
1715                        cam->params.colourBalance.greenGain = data[1];
1716                        cam->params.colourBalance.blueGain = data[2];
1717                        mutex_unlock(&cam->param_lock);
1718                        break;
1719                case CPIA_COMMAND_GetExposure:
1720                        cam->params.exposure.gain = data[0];
1721                        cam->params.exposure.fineExp = data[1];
1722                        cam->params.exposure.coarseExpLo = data[2];
1723                        cam->params.exposure.coarseExpHi = data[3];
1724                        cam->params.exposure.redComp = data[4];
1725                        cam->params.exposure.green1Comp = data[5];
1726                        cam->params.exposure.green2Comp = data[6];
1727                        cam->params.exposure.blueComp = data[7];
1728                        mutex_unlock(&cam->param_lock);
1729                        break;
1730
1731                case CPIA_COMMAND_ReadMCPorts:
1732                        if (!cam->params.qx3.qx3_detected)
1733                                break;
1734                        /* test button press */
1735                        cam->params.qx3.button = ((data[1] & 0x02) == 0);
1736                        if (cam->params.qx3.button) {
1737                                /* button pressed - unlock the latch */
1738                                do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
1739                                do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
1740                        }
1741
1742                        /* test whether microscope is cradled */
1743                        cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
1744                        break;
1745
1746                default:
1747                        break;
1748                }
1749        }
1750        return retval;
1751}
1752
1753/* send a command  to the camera with an additional data transaction */
1754static int do_command_extended(struct cam_data *cam, u16 command,
1755                               u8 a, u8 b, u8 c, u8 d,
1756                               u8 e, u8 f, u8 g, u8 h,
1757                               u8 i, u8 j, u8 k, u8 l)
1758{
1759        int retval;
1760        u8 cmd[8], data[8];
1761
1762        cmd[0] = command>>8;
1763        cmd[1] = command&0xff;
1764        cmd[2] = a;
1765        cmd[3] = b;
1766        cmd[4] = c;
1767        cmd[5] = d;
1768        cmd[6] = 8;
1769        cmd[7] = 0;
1770        data[0] = e;
1771        data[1] = f;
1772        data[2] = g;
1773        data[3] = h;
1774        data[4] = i;
1775        data[5] = j;
1776        data[6] = k;
1777        data[7] = l;
1778
1779        retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1780        if (retval)
1781                DBG("%x - failed\n", command);
1782
1783        return retval;
1784}
1785
1786/**********************************************************************
1787 *
1788 * Colorspace conversion
1789 *
1790 **********************************************************************/
1791#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1792
1793static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1794                      int linesize, int mmap_kludge)
1795{
1796        int y, u, v, r, g, b, y1;
1797
1798        /* Odd lines use the same u and v as the previous line.
1799         * Because of compression, it is necessary to get this
1800         * information from the decoded image. */
1801        switch(out_fmt) {
1802        case VIDEO_PALETTE_RGB555:
1803                y = (*yuv++ - 16) * 76310;
1804                y1 = (*yuv - 16) * 76310;
1805                r = ((*(rgb+1-linesize)) & 0x7c) << 1;
1806                g = ((*(rgb-linesize)) & 0xe0) >> 4 |
1807                    ((*(rgb+1-linesize)) & 0x03) << 6;
1808                b = ((*(rgb-linesize)) & 0x1f) << 3;
1809                u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1810                v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1811                r = 104635 * v;
1812                g = -25690 * u - 53294 * v;
1813                b = 132278 * u;
1814                *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1815                *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1816                *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1817                *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1818                return 4;
1819        case VIDEO_PALETTE_RGB565:
1820                y = (*yuv++ - 16) * 76310;
1821                y1 = (*yuv - 16) * 76310;
1822                r = (*(rgb+1-linesize)) & 0xf8;
1823                g = ((*(rgb-linesize)) & 0xe0) >> 3 |
1824                    ((*(rgb+1-linesize)) & 0x07) << 5;
1825                b = ((*(rgb-linesize)) & 0x1f) << 3;
1826                u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1827                v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1828                r = 104635 * v;
1829                g = -25690 * u - 53294 * v;
1830                b = 132278 * u;
1831                *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1832                *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1833                *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1834                *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1835                return 4;
1836                break;
1837        case VIDEO_PALETTE_RGB24:
1838        case VIDEO_PALETTE_RGB32:
1839                y = (*yuv++ - 16) * 76310;
1840                y1 = (*yuv - 16) * 76310;
1841                if (mmap_kludge) {
1842                        r = *(rgb+2-linesize);
1843                        g = *(rgb+1-linesize);
1844                        b = *(rgb-linesize);
1845                } else {
1846                        r = *(rgb-linesize);
1847                        g = *(rgb+1-linesize);
1848                        b = *(rgb+2-linesize);
1849                }
1850                u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1851                v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1852                r = 104635 * v;
1853                g = -25690 * u + -53294 * v;
1854                b = 132278 * u;
1855                if (mmap_kludge) {
1856                        *rgb++ = LIMIT(b+y);
1857                        *rgb++ = LIMIT(g+y);
1858                        *rgb++ = LIMIT(r+y);
1859                        if(out_fmt == VIDEO_PALETTE_RGB32)
1860                                rgb++;
1861                        *rgb++ = LIMIT(b+y1);
1862                        *rgb++ = LIMIT(g+y1);
1863                        *rgb = LIMIT(r+y1);
1864                } else {
1865                        *rgb++ = LIMIT(r+y);
1866                        *rgb++ = LIMIT(g+y);
1867                        *rgb++ = LIMIT(b+y);
1868                        if(out_fmt == VIDEO_PALETTE_RGB32)
1869                                rgb++;
1870                        *rgb++ = LIMIT(r+y1);
1871                        *rgb++ = LIMIT(g+y1);
1872                        *rgb = LIMIT(b+y1);
1873                }
1874                if(out_fmt == VIDEO_PALETTE_RGB32)
1875                        return 8;
1876                return 6;
1877        case VIDEO_PALETTE_YUV422:
1878        case VIDEO_PALETTE_YUYV:
1879                y = *yuv++;
1880                u = *(rgb+1-linesize);
1881                y1 = *yuv;
1882                v = *(rgb+3-linesize);
1883                *rgb++ = y;
1884                *rgb++ = u;
1885                *rgb++ = y1;
1886                *rgb = v;
1887                return 4;
1888        case VIDEO_PALETTE_UYVY:
1889                u = *(rgb-linesize);
1890                y = *yuv++;
1891                v = *(rgb+2-linesize);
1892                y1 = *yuv;
1893                *rgb++ = u;
1894                *rgb++ = y;
1895                *rgb++ = v;
1896                *rgb = y1;
1897                return 4;
1898        case VIDEO_PALETTE_GREY:
1899                *rgb++ = *yuv++;
1900                *rgb = *yuv;
1901                return 2;
1902        default:
1903                DBG("Empty: %d\n", out_fmt);
1904                return 0;
1905        }
1906}
1907
1908
1909static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1910                      int in_uyvy, int mmap_kludge)
1911{
1912        int y, u, v, r, g, b, y1;
1913
1914        switch(out_fmt) {
1915        case VIDEO_PALETTE_RGB555:
1916        case VIDEO_PALETTE_RGB565:
1917        case VIDEO_PALETTE_RGB24:
1918        case VIDEO_PALETTE_RGB32:
1919                if (in_uyvy) {
1920                        u = *yuv++ - 128;
1921                        y = (*yuv++ - 16) * 76310;
1922                        v = *yuv++ - 128;
1923                        y1 = (*yuv - 16) * 76310;
1924                } else {
1925                        y = (*yuv++ - 16) * 76310;
1926                        u = *yuv++ - 128;
1927                        y1 = (*yuv++ - 16) * 76310;
1928                        v = *yuv - 128;
1929                }
1930                r = 104635 * v;
1931                g = -25690 * u + -53294 * v;
1932                b = 132278 * u;
1933                break;
1934        default:
1935                y = *yuv++;
1936                u = *yuv++;
1937                y1 = *yuv++;
1938                v = *yuv;
1939                /* Just to avoid compiler warnings */
1940                r = 0;
1941                g = 0;
1942                b = 0;
1943                break;
1944        }
1945        switch(out_fmt) {
1946        case VIDEO_PALETTE_RGB555:
1947                *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1948                *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1949                *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1950                *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1951                return 4;
1952        case VIDEO_PALETTE_RGB565:
1953                *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1954                *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1955                *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1956                *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1957                return 4;
1958        case VIDEO_PALETTE_RGB24:
1959                if (mmap_kludge) {
1960                        *rgb++ = LIMIT(b+y);
1961                        *rgb++ = LIMIT(g+y);
1962                        *rgb++ = LIMIT(r+y);
1963                        *rgb++ = LIMIT(b+y1);
1964                        *rgb++ = LIMIT(g+y1);
1965                        *rgb = LIMIT(r+y1);
1966                } else {
1967                        *rgb++ = LIMIT(r+y);
1968                        *rgb++ = LIMIT(g+y);
1969                        *rgb++ = LIMIT(b+y);
1970                        *rgb++ = LIMIT(r+y1);
1971                        *rgb++ = LIMIT(g+y1);
1972                        *rgb = LIMIT(b+y1);
1973                }
1974                return 6;
1975        case VIDEO_PALETTE_RGB32:
1976                if (mmap_kludge) {
1977                        *rgb++ = LIMIT(b+y);
1978                        *rgb++ = LIMIT(g+y);
1979                        *rgb++ = LIMIT(r+y);
1980                        rgb++;
1981                        *rgb++ = LIMIT(b+y1);
1982                        *rgb++ = LIMIT(g+y1);
1983                        *rgb = LIMIT(r+y1);
1984                } else {
1985                        *rgb++ = LIMIT(r+y);
1986                        *rgb++ = LIMIT(g+y);
1987                        *rgb++ = LIMIT(b+y);
1988                        rgb++;
1989                        *rgb++ = LIMIT(r+y1);
1990                        *rgb++ = LIMIT(g+y1);
1991                        *rgb = LIMIT(b+y1);
1992                }
1993                return 8;
1994        case VIDEO_PALETTE_GREY:
1995                *rgb++ = y;
1996                *rgb = y1;
1997                return 2;
1998        case VIDEO_PALETTE_YUV422:
1999        case VIDEO_PALETTE_YUYV:
2000                *rgb++ = y;
2001                *rgb++ = u;
2002                *rgb++ = y1;
2003                *rgb = v;
2004                return 4;
2005        case VIDEO_PALETTE_UYVY:
2006                *rgb++ = u;
2007                *rgb++ = y;
2008                *rgb++ = v;
2009                *rgb = y1;
2010                return 4;
2011        default:
2012                DBG("Empty: %d\n", out_fmt);
2013                return 0;
2014        }
2015}
2016
2017static int skipcount(int count, int fmt)
2018{
2019        switch(fmt) {
2020        case VIDEO_PALETTE_GREY:
2021                return count;
2022        case VIDEO_PALETTE_RGB555:
2023        case VIDEO_PALETTE_RGB565:
2024        case VIDEO_PALETTE_YUV422:
2025        case VIDEO_PALETTE_YUYV:
2026        case VIDEO_PALETTE_UYVY:
2027                return 2*count;
2028        case VIDEO_PALETTE_RGB24:
2029                return 3*count;
2030        case VIDEO_PALETTE_RGB32:
2031                return 4*count;
2032        default:
2033                return 0;
2034        }
2035}
2036
2037static int parse_picture(struct cam_data *cam, int size)
2038{
2039        u8 *obuf, *ibuf, *end_obuf;
2040        int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
2041        int rows, cols, linesize, subsample_422;
2042
2043        /* make sure params don't change while we are decoding */
2044        mutex_lock(&cam->param_lock);
2045
2046        obuf = cam->decompressed_frame.data;
2047        end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
2048        ibuf = cam->raw_image;
2049        origsize = size;
2050        out_fmt = cam->vp.palette;
2051
2052        if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
2053                LOG("header not found\n");
2054                mutex_unlock(&cam->param_lock);
2055                return -1;
2056        }
2057
2058        if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
2059                LOG("wrong video size\n");
2060                mutex_unlock(&cam->param_lock);
2061                return -1;
2062        }
2063
2064        if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
2065                LOG("illegal subtype %d\n",ibuf[17]);
2066                mutex_unlock(&cam->param_lock);
2067                return -1;
2068        }
2069        subsample_422 = ibuf[17] == SUBSAMPLE_422;
2070
2071        if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
2072                LOG("illegal yuvorder %d\n",ibuf[18]);
2073                mutex_unlock(&cam->param_lock);
2074                return -1;
2075        }
2076        in_uyvy = ibuf[18] == YUVORDER_UYVY;
2077
2078        if ((ibuf[24] != cam->params.roi.colStart) ||
2079            (ibuf[25] != cam->params.roi.colEnd) ||
2080            (ibuf[26] != cam->params.roi.rowStart) ||
2081            (ibuf[27] != cam->params.roi.rowEnd)) {
2082                LOG("ROI mismatch\n");
2083                mutex_unlock(&cam->param_lock);
2084                return -1;
2085        }
2086        cols = 8*(ibuf[25] - ibuf[24]);
2087        rows = 4*(ibuf[27] - ibuf[26]);
2088
2089
2090        if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
2091                LOG("illegal compression %d\n",ibuf[28]);
2092                mutex_unlock(&cam->param_lock);
2093                return -1;
2094        }
2095        compressed = (ibuf[28] == COMPRESSED);
2096
2097        if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
2098                LOG("illegal decimation %d\n",ibuf[29]);
2099                mutex_unlock(&cam->param_lock);
2100                return -1;
2101        }
2102        decimation = (ibuf[29] == DECIMATION_ENAB);
2103
2104        cam->params.yuvThreshold.yThreshold = ibuf[30];
2105        cam->params.yuvThreshold.uvThreshold = ibuf[31];
2106        cam->params.status.systemState = ibuf[32];
2107        cam->params.status.grabState = ibuf[33];
2108        cam->params.status.streamState = ibuf[34];
2109        cam->params.status.fatalError = ibuf[35];
2110        cam->params.status.cmdError = ibuf[36];
2111        cam->params.status.debugFlags = ibuf[37];
2112        cam->params.status.vpStatus = ibuf[38];
2113        cam->params.status.errorCode = ibuf[39];
2114        cam->fps = ibuf[41];
2115        mutex_unlock(&cam->param_lock);
2116
2117        linesize = skipcount(cols, out_fmt);
2118        ibuf += FRAME_HEADER_SIZE;
2119        size -= FRAME_HEADER_SIZE;
2120        ll = ibuf[0] | (ibuf[1] << 8);
2121        ibuf += 2;
2122        even_line = 1;
2123
2124        while (size > 0) {
2125                size -= (ll+2);
2126                if (size < 0) {
2127                        LOG("Insufficient data in buffer\n");
2128                        return -1;
2129                }
2130
2131                while (ll > 1) {
2132                        if (!compressed || (compressed && !(*ibuf & 1))) {
2133                                if(subsample_422 || even_line) {
2134                                obuf += yuvconvert(ibuf, obuf, out_fmt,
2135                                                   in_uyvy, cam->mmap_kludge);
2136                                ibuf += 4;
2137                                ll -= 4;
2138                        } else {
2139                                        /* SUBSAMPLE_420 on an odd line */
2140                                        obuf += convert420(ibuf, obuf,
2141                                                           out_fmt, linesize,
2142                                                           cam->mmap_kludge);
2143                                        ibuf += 2;
2144                                        ll -= 2;
2145                                }
2146                        } else {
2147                                /*skip compressed interval from previous frame*/
2148                                obuf += skipcount(*ibuf >> 1, out_fmt);
2149                                if (obuf > end_obuf) {
2150                                        LOG("Insufficient buffer size\n");
2151                                        return -1;
2152                                }
2153                                ++ibuf;
2154                                ll--;
2155                        }
2156                }
2157                if (ll == 1) {
2158                        if (*ibuf != EOL) {
2159                                DBG("EOL not found giving up after %d/%d"
2160                                    " bytes\n", origsize-size, origsize);
2161                                return -1;
2162                        }
2163
2164                        ++ibuf; /* skip over EOL */
2165
2166                        if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
2167                           (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
2168                                size -= 4;
2169                                break;
2170                        }
2171
2172                        if(decimation) {
2173                                /* skip the odd lines for now */
2174                                obuf += linesize;
2175                        }
2176
2177                        if (size > 1) {
2178                                ll = ibuf[0] | (ibuf[1] << 8);
2179                                ibuf += 2; /* skip over line length */
2180                        }
2181                        if(!decimation)
2182                                even_line = !even_line;
2183                } else {
2184                        LOG("line length was not 1 but %d after %d/%d bytes\n",
2185                            ll, origsize-size, origsize);
2186                        return -1;
2187                }
2188        }
2189
2190        if(decimation) {
2191                /* interpolate odd rows */
2192                int i, j;
2193                u8 *prev, *next;
2194                prev = cam->decompressed_frame.data;
2195                obuf = prev+linesize;
2196                next = obuf+linesize;
2197                for(i=1; i<rows-1; i+=2) {
2198                        for(j=0; j<linesize; ++j) {
2199                                *obuf++ = ((int)*prev++ + *next++) / 2;
2200                        }
2201                        prev += linesize;
2202                        obuf += linesize;
2203                        next += linesize;
2204                }
2205                /* last row is odd, just copy previous row */
2206                memcpy(obuf, prev, linesize);
2207        }
2208
2209        cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
2210
2211        return cam->decompressed_frame.count;
2212}
2213
2214/* InitStreamCap wrapper to select correct start line */
2215static inline int init_stream_cap(struct cam_data *cam)
2216{
2217        return do_command(cam, CPIA_COMMAND_InitStreamCap,
2218                          0, cam->params.streamStartLine, 0, 0);
2219}
2220
2221
2222/*  find_over_exposure
2223 *    Finds a suitable value of OverExposure for use with SetFlickerCtrl
2224 *    Some calculation is required because this value changes with the brightness
2225 *    set with SetColourParameters
2226 *
2227 *  Parameters: Brightness  -  last brightness value set with SetColourParameters
2228 *
2229 *  Returns: OverExposure value to use with SetFlickerCtrl
2230 */
2231#define FLICKER_MAX_EXPOSURE                    250
2232#define FLICKER_ALLOWABLE_OVER_EXPOSURE         146
2233#define FLICKER_BRIGHTNESS_CONSTANT             59
2234static int find_over_exposure(int brightness)
2235{
2236        int MaxAllowableOverExposure, OverExposure;
2237
2238        MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
2239                                   FLICKER_BRIGHTNESS_CONSTANT;
2240
2241        if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
2242                OverExposure = MaxAllowableOverExposure;
2243        } else {
2244                OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
2245        }
2246
2247        return OverExposure;
2248}
2249#undef FLICKER_MAX_EXPOSURE
2250#undef FLICKER_ALLOWABLE_OVER_EXPOSURE
2251#undef FLICKER_BRIGHTNESS_CONSTANT
2252
2253/* update various camera modes and settings */
2254static void dispatch_commands(struct cam_data *cam)
2255{
2256        mutex_lock(&cam->param_lock);
2257        if (cam->cmd_queue==COMMAND_NONE) {
2258                mutex_unlock(&cam->param_lock);
2259                return;
2260        }
2261        DEB_BYTE(cam->cmd_queue);
2262        DEB_BYTE(cam->cmd_queue>>8);
2263        if (cam->cmd_queue & COMMAND_SETFORMAT) {
2264                do_command(cam, CPIA_COMMAND_SetFormat,
2265                           cam->params.format.videoSize,
2266                           cam->params.format.subSample,
2267                           cam->params.format.yuvOrder, 0);
2268                do_command(cam, CPIA_COMMAND_SetROI,
2269                           cam->params.roi.colStart, cam->params.roi.colEnd,
2270                           cam->params.roi.rowStart, cam->params.roi.rowEnd);
2271                cam->first_frame = 1;
2272        }
2273
2274        if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
2275                do_command(cam, CPIA_COMMAND_SetColourParams,
2276                           cam->params.colourParams.brightness,
2277                           cam->params.colourParams.contrast,
2278                           cam->params.colourParams.saturation, 0);
2279
2280        if (cam->cmd_queue & COMMAND_SETAPCOR)
2281                do_command(cam, CPIA_COMMAND_SetApcor,
2282                           cam->params.apcor.gain1,
2283                           cam->params.apcor.gain2,
2284                           cam->params.apcor.gain4,
2285                           cam->params.apcor.gain8);
2286
2287        if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2288                do_command(cam, CPIA_COMMAND_SetVLOffset,
2289                           cam->params.vlOffset.gain1,
2290                           cam->params.vlOffset.gain2,
2291                           cam->params.vlOffset.gain4,
2292                           cam->params.vlOffset.gain8);
2293
2294        if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
2295                do_command_extended(cam, CPIA_COMMAND_SetExposure,
2296                                    cam->params.exposure.gainMode,
2297                                    1,
2298                                    cam->params.exposure.compMode,
2299                                    cam->params.exposure.centreWeight,
2300                                    cam->params.exposure.gain,
2301                                    cam->params.exposure.fineExp,
2302                                    cam->params.exposure.coarseExpLo,
2303                                    cam->params.exposure.coarseExpHi,
2304                                    cam->params.exposure.redComp,
2305                                    cam->params.exposure.green1Comp,
2306                                    cam->params.exposure.green2Comp,
2307                                    cam->params.exposure.blueComp);
2308                if(cam->params.exposure.expMode != 1) {
2309                        do_command_extended(cam, CPIA_COMMAND_SetExposure,
2310                                            0,
2311                                            cam->params.exposure.expMode,
2312                                            0, 0,
2313                                            cam->params.exposure.gain,
2314                                            cam->params.exposure.fineExp,
2315                                            cam->params.exposure.coarseExpLo,
2316                                            cam->params.exposure.coarseExpHi,
2317                                            0, 0, 0, 0);
2318                }
2319        }
2320
2321        if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2322                if (cam->params.colourBalance.balanceMode == 1) {
2323                        do_command(cam, CPIA_COMMAND_SetColourBalance,
2324                                   1,
2325                                   cam->params.colourBalance.redGain,
2326                                   cam->params.colourBalance.greenGain,
2327                                   cam->params.colourBalance.blueGain);
2328                        do_command(cam, CPIA_COMMAND_SetColourBalance,
2329                                   3, 0, 0, 0);
2330                }
2331                if (cam->params.colourBalance.balanceMode == 2) {
2332                        do_command(cam, CPIA_COMMAND_SetColourBalance,
2333                                   2, 0, 0, 0);
2334                }
2335                if (cam->params.colourBalance.balanceMode == 3) {
2336                        do_command(cam, CPIA_COMMAND_SetColourBalance,
2337                                   3, 0, 0, 0);
2338                }
2339        }
2340
2341        if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2342                do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2343                           cam->params.compressionTarget.frTargeting,
2344                           cam->params.compressionTarget.targetFR,
2345                           cam->params.compressionTarget.targetQ, 0);
2346
2347        if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2348                do_command(cam, CPIA_COMMAND_SetYUVThresh,
2349                           cam->params.yuvThreshold.yThreshold,
2350                           cam->params.yuvThreshold.uvThreshold, 0, 0);
2351
2352        if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2353                do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2354                            0, 0, 0, 0,
2355                            cam->params.compressionParams.hysteresis,
2356                            cam->params.compressionParams.threshMax,
2357                            cam->params.compressionParams.smallStep,
2358                            cam->params.compressionParams.largeStep,
2359                            cam->params.compressionParams.decimationHysteresis,
2360                            cam->params.compressionParams.frDiffStepThresh,
2361                            cam->params.compressionParams.qDiffStepThresh,
2362                            cam->params.compressionParams.decimationThreshMod);
2363
2364        if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2365                do_command(cam, CPIA_COMMAND_SetCompression,
2366                           cam->params.compression.mode,
2367                           cam->params.compression.decimation, 0, 0);
2368
2369        if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2370                do_command(cam, CPIA_COMMAND_SetSensorFPS,
2371                           cam->params.sensorFps.divisor,
2372                           cam->params.sensorFps.baserate, 0, 0);
2373
2374        if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2375                do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2376                           cam->params.flickerControl.flickerMode,
2377                           cam->params.flickerControl.coarseJump,
2378                           abs(cam->params.flickerControl.allowableOverExposure),
2379                           0);
2380
2381        if (cam->cmd_queue & COMMAND_SETECPTIMING)
2382                do_command(cam, CPIA_COMMAND_SetECPTiming,
2383                           cam->params.ecpTiming, 0, 0, 0);
2384
2385        if (cam->cmd_queue & COMMAND_PAUSE)
2386                do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2387
2388        if (cam->cmd_queue & COMMAND_RESUME)
2389                init_stream_cap(cam);
2390
2391        if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
2392          {
2393            int p1 = (cam->params.qx3.bottomlight == 0) << 1;
2394            int p2 = (cam->params.qx3.toplight == 0) << 3;
2395            do_command(cam, CPIA_COMMAND_WriteVCReg,  0x90, 0x8F, 0x50, 0);
2396            do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
2397          }
2398
2399        cam->cmd_queue = COMMAND_NONE;
2400        mutex_unlock(&cam->param_lock);
2401        return;
2402}
2403
2404
2405
2406static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
2407                        int on)
2408{
2409        /* Everything in here is from the Windows driver */
2410#define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2411                               params->version.firmwareRevision == (y))
2412/* define for compgain calculation */
2413#if 0
2414#define COMPGAIN(base, curexp, newexp) \
2415    (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
2416#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2417    (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
2418#else
2419  /* equivalent functions without floating point math */
2420#define COMPGAIN(base, curexp, newexp) \
2421    (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
2422#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2423     (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
2424#endif
2425
2426
2427        int currentexp = params->exposure.coarseExpLo +
2428                         params->exposure.coarseExpHi*256;
2429        int startexp;
2430        if (on) {
2431                int cj = params->flickerControl.coarseJump;
2432                params->flickerControl.flickerMode = 1;
2433                params->flickerControl.disabled = 0;
2434                if(params->exposure.expMode != 2)
2435                        *command_flags |= COMMAND_SETEXPOSURE;
2436                params->exposure.expMode = 2;
2437                currentexp = currentexp << params->exposure.gain;
2438                params->exposure.gain = 0;
2439                /* round down current exposure to nearest value */
2440                startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
2441                if(startexp < 1)
2442                        startexp = 1;
2443                startexp = (startexp * cj) - 1;
2444                if(FIRMWARE_VERSION(1,2))
2445                        while(startexp > MAX_EXP_102)
2446                                startexp -= cj;
2447                else
2448                        while(startexp > MAX_EXP)
2449                                startexp -= cj;
2450                params->exposure.coarseExpLo = startexp & 0xff;
2451                params->exposure.coarseExpHi = startexp >> 8;
2452                if (currentexp > startexp) {
2453                        if (currentexp > (2 * startexp))
2454                                currentexp = 2 * startexp;
2455                        params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp);
2456                        params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp);
2457                        params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp);
2458                        params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp);
2459                } else {
2460                        params->exposure.redComp = COMP_RED;
2461                        params->exposure.green1Comp = COMP_GREEN1;
2462                        params->exposure.green2Comp = COMP_GREEN2;
2463                        params->exposure.blueComp = COMP_BLUE;
2464                }
2465                if(FIRMWARE_VERSION(1,2))
2466                        params->exposure.compMode = 0;
2467                else
2468                        params->exposure.compMode = 1;
2469
2470                params->apcor.gain1 = 0x18;
2471                params->apcor.gain2 = 0x18;
2472                params->apcor.gain4 = 0x16;
2473                params->apcor.gain8 = 0x14;
2474                *command_flags |= COMMAND_SETAPCOR;
2475        } else {
2476                params->flickerControl.flickerMode = 0;
2477                params->flickerControl.disabled = 1;
2478                /* Coarse = average of equivalent coarse for each comp channel */
2479                startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp);
2480                startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp);
2481                startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp);
2482                startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp);
2483                startexp = startexp >> 2;
2484                while(startexp > MAX_EXP &&
2485                      params->exposure.gain < params->exposure.gainMode-1) {
2486                        startexp = startexp >> 1;
2487                        ++params->exposure.gain;
2488                }
2489                if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102)
2490                        startexp = MAX_EXP_102;
2491                if(startexp > MAX_EXP)
2492                        startexp = MAX_EXP;
2493                params->exposure.coarseExpLo = startexp&0xff;
2494                params->exposure.coarseExpHi = startexp >> 8;
2495                params->exposure.redComp = COMP_RED;
2496                params->exposure.green1Comp = COMP_GREEN1;
2497                params->exposure.green2Comp = COMP_GREEN2;
2498                params->exposure.blueComp = COMP_BLUE;
2499                params->exposure.compMode = 1;
2500                *command_flags |= COMMAND_SETEXPOSURE;
2501                params->apcor.gain1 = 0x18;
2502                params->apcor.gain2 = 0x16;
2503                params->apcor.gain4 = 0x24;
2504                params->apcor.gain8 = 0x34;
2505                *command_flags |= COMMAND_SETAPCOR;
2506        }
2507        params->vlOffset.gain1 = 20;
2508        params->vlOffset.gain2 = 24;
2509        params->vlOffset.gain4 = 26;
2510        params->vlOffset.gain8 = 26;
2511        *command_flags |= COMMAND_SETVLOFFSET;
2512#undef FIRMWARE_VERSION
2513#undef EXP_FROM_COMP
2514#undef COMPGAIN
2515}
2516
2517#define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
2518                               cam->params.version.firmwareRevision == (y))
2519/* monitor the exposure and adjust the sensor frame rate if needed */
2520static void monitor_exposure(struct cam_data *cam)
2521{
2522        u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
2523        int retval, light_exp, dark_exp, very_dark_exp;
2524        int old_exposure, new_exposure, framerate;
2525
2526        /* get necessary stats and register settings from camera */
2527        /* do_command can't handle this, so do it ourselves */
2528        cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
2529        cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff;
2530        cmd[2] = 30;
2531        cmd[3] = 4;
2532        cmd[4] = 9;
2533        cmd[5] = 8;
2534        cmd[6] = 8;
2535        cmd[7] = 0;
2536        retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
2537        if (retval) {
2538                LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
2539                    retval);
2540                return;
2541        }
2542        exp_acc = data[0];
2543        bcomp = data[1];
2544        gain = data[2];
2545        coarseL = data[3];
2546
2547        mutex_lock(&cam->param_lock);
2548        light_exp = cam->params.colourParams.brightness +
2549                    TC - 50 + EXP_ACC_LIGHT;
2550        if(light_exp > 255)
2551                light_exp = 255;
2552        dark_exp = cam->params.colourParams.brightness +
2553                   TC - 50 - EXP_ACC_DARK;
2554        if(dark_exp < 0)
2555                dark_exp = 0;
2556        very_dark_exp = dark_exp/2;
2557
2558        old_exposure = cam->params.exposure.coarseExpHi * 256 +
2559                       cam->params.exposure.coarseExpLo;
2560
2561        if(!cam->params.flickerControl.disabled) {
2562                /* Flicker control on */
2563                int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102;
2564                bcomp += 128;        /* decode */
2565                if(bcomp >= max_comp && exp_acc < dark_exp) {
2566                        /* dark */
2567                        if(exp_acc < very_dark_exp) {
2568                                /* very dark */
2569                                if(cam->exposure_status == EXPOSURE_VERY_DARK)
2570                                        ++cam->exposure_count;
2571                                else {
2572                                        cam->exposure_status = EXPOSURE_VERY_DARK;
2573                                        cam->exposure_count = 1;
2574                                }
2575                        } else {
2576                                /* just dark */
2577                                if(cam->exposure_status == EXPOSURE_DARK)
2578                                        ++cam->exposure_count;
2579                                else {
2580                                        cam->exposure_status = EXPOSURE_DARK;
2581                                        cam->exposure_count = 1;
2582                                }
2583                        }
2584                } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2585                        /* light */
2586                        if(old_exposure <= VERY_LOW_EXP) {
2587                                /* very light */
2588                                if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2589                                        ++cam->exposure_count;
2590                                else {
2591                                        cam->exposure_status = EXPOSURE_VERY_LIGHT;
2592                                        cam->exposure_count = 1;
2593                                }
2594                        } else {
2595                                /* just light */
2596                                if(cam->exposure_status == EXPOSURE_LIGHT)
2597                                        ++cam->exposure_count;
2598                                else {
2599                                        cam->exposure_status = EXPOSURE_LIGHT;
2600                                        cam->exposure_count = 1;
2601                                }
2602                        }
2603                } else {
2604                        /* not dark or light */
2605                        cam->exposure_status = EXPOSURE_NORMAL;
2606                }
2607        } else {
2608                /* Flicker control off */
2609                if(old_exposure >= MAX_EXP && exp_acc < dark_exp) {
2610                        /* dark */
2611                        if(exp_acc < very_dark_exp) {
2612                                /* very dark */
2613                                if(cam->exposure_status == EXPOSURE_VERY_DARK)
2614                                        ++cam->exposure_count;
2615                                else {
2616                                        cam->exposure_status = EXPOSURE_VERY_DARK;
2617                                        cam->exposure_count = 1;
2618                                }
2619                        } else {
2620                                /* just dark */
2621                                if(cam->exposure_status == EXPOSURE_DARK)
2622                                        ++cam->exposure_count;
2623                                else {
2624                                        cam->exposure_status = EXPOSURE_DARK;
2625                                        cam->exposure_count = 1;
2626                                }
2627                        }
2628                } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2629                        /* light */
2630                        if(old_exposure <= VERY_LOW_EXP) {
2631                                /* very light */
2632                                if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2633                                        ++cam->exposure_count;
2634                                else {
2635                                        cam->exposure_status = EXPOSURE_VERY_LIGHT;
2636                                        cam->exposure_count = 1;
2637                                }
2638                        } else {
2639                                /* just light */
2640                                if(cam->exposure_status == EXPOSURE_LIGHT)
2641                                        ++cam->exposure_count;
2642                                else {
2643                                        cam->exposure_status = EXPOSURE_LIGHT;
2644                                        cam->exposure_count = 1;
2645                                }
2646                        }
2647                } else {
2648                        /* not dark or light */
2649                        cam->exposure_status = EXPOSURE_NORMAL;
2650                }
2651        }
2652
2653        framerate = cam->fps;
2654        if(framerate > 30 || framerate < 1)
2655                framerate = 1;
2656
2657        if(!cam->params.flickerControl.disabled) {
2658                /* Flicker control on */
2659                if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2660                    cam->exposure_status == EXPOSURE_DARK) &&
2661                   cam->exposure_count >= DARK_TIME*framerate &&
2662                   cam->params.sensorFps.divisor < 3) {
2663
2664                        /* dark for too long */
2665                        ++cam->params.sensorFps.divisor;
2666                        cam->cmd_queue |= COMMAND_SETSENSORFPS;
2667
2668                        cam->params.flickerControl.coarseJump =
2669                                flicker_jumps[cam->mainsFreq]
2670                                             [cam->params.sensorFps.baserate]
2671                                             [cam->params.sensorFps.divisor];
2672                        cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2673
2674                        new_exposure = cam->params.flickerControl.coarseJump-1;
2675                        while(new_exposure < old_exposure/2)
2676                                new_exposure += cam->params.flickerControl.coarseJump;
2677                        cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2678                        cam->params.exposure.coarseExpHi = new_exposure >> 8;
2679                        cam->cmd_queue |= COMMAND_SETEXPOSURE;
2680                        cam->exposure_status = EXPOSURE_NORMAL;
2681                        LOG("Automatically decreasing sensor_fps\n");
2682
2683                } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2684                    cam->exposure_status == EXPOSURE_LIGHT) &&
2685                   cam->exposure_count >= LIGHT_TIME*framerate &&
2686                   cam->params.sensorFps.divisor > 0) {
2687
2688                        /* light for too long */
2689                        int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
2690
2691                        --cam->params.sensorFps.divisor;
2692                        cam->cmd_queue |= COMMAND_SETSENSORFPS;
2693
2694                        cam->params.flickerControl.coarseJump =
2695                                flicker_jumps[cam->mainsFreq]
2696                                             [cam->params.sensorFps.baserate]
2697                                             [cam->params.sensorFps.divisor];
2698                        cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2699
2700                        new_exposure = cam->params.flickerControl.coarseJump-1;
2701                        while(new_exposure < 2*old_exposure &&
2702                              new_exposure+
2703                              cam->params.flickerControl.coarseJump < max_exp)
2704                                new_exposure += cam->params.flickerControl.coarseJump;
2705                        cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2706                        cam->params.exposure.coarseExpHi = new_exposure >> 8;
2707                        cam->cmd_queue |= COMMAND_SETEXPOSURE;
2708                        cam->exposure_status = EXPOSURE_NORMAL;
2709                        LOG("Automatically increasing sensor_fps\n");
2710                }
2711        } else {
2712                /* Flicker control off */
2713                if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2714                    cam->exposure_status == EXPOSURE_DARK) &&
2715                   cam->exposure_count >= DARK_TIME*framerate &&
2716                   cam->params.sensorFps.divisor < 3) {
2717
2718                        /* dark for too long */
2719                        ++cam->params.sensorFps.divisor;
2720                        cam->cmd_queue |= COMMAND_SETSENSORFPS;
2721
2722                        if(cam->params.exposure.gain > 0) {
2723                                --cam->params.exposure.gain;
2724                                cam->cmd_queue |= COMMAND_SETEXPOSURE;
2725                        }
2726                        cam->exposure_status = EXPOSURE_NORMAL;
2727                        LOG("Automatically decreasing sensor_fps\n");
2728
2729                } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2730                    cam->exposure_status == EXPOSURE_LIGHT) &&
2731                   cam->exposure_count >= LIGHT_TIME*framerate &&
2732                   cam->params.sensorFps.divisor > 0) {
2733
2734                        /* light for too long */
2735                        --cam->params.sensorFps.divisor;
2736                        cam->cmd_queue |= COMMAND_SETSENSORFPS;
2737
2738                        if(cam->params.exposure.gain <
2739                           cam->params.exposure.gainMode-1) {
2740                                ++cam->params.exposure.gain;
2741                                cam->cmd_queue |= COMMAND_SETEXPOSURE;
2742                        }
2743                        cam->exposure_status = EXPOSURE_NORMAL;
2744                        LOG("Automatically increasing sensor_fps\n");
2745                }
2746        }
2747        mutex_unlock(&cam->param_lock);
2748}
2749
2750/*-----------------------------------------------------------------*/
2751/* if flicker is switched off, this function switches it back on.It checks,
2752   however, that conditions are suitable before restarting it.
2753   This should only be called for firmware version 1.2.
2754
2755   It also adjust the colour balance when an exposure step is detected - as
2756   long as flicker is running
2757*/
2758static void restart_flicker(struct cam_data *cam)
2759{
2760        int cam_exposure, old_exp;
2761        if(!FIRMWARE_VERSION(1,2))
2762                return;
2763        mutex_lock(&cam->param_lock);
2764        if(cam->params.flickerControl.flickerMode == 0 ||
2765           cam->raw_image[39] == 0) {
2766                mutex_unlock(&cam->param_lock);
2767                return;
2768        }
2769        cam_exposure = cam->raw_image[39]*2;
2770        old_exp = cam->params.exposure.coarseExpLo +
2771                  cam->params.exposure.coarseExpHi*256;
2772        /*
2773          see how far away camera exposure is from a valid
2774          flicker exposure value
2775        */
2776        cam_exposure %= cam->params.flickerControl.coarseJump;
2777        if(!cam->params.flickerControl.disabled &&
2778           cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
2779                /* Flicker control auto-disabled */
2780                cam->params.flickerControl.disabled = 1;
2781        }
2782
2783        if(cam->params.flickerControl.disabled &&
2784           cam->params.flickerControl.flickerMode &&
2785           old_exp > cam->params.flickerControl.coarseJump +
2786                     ROUND_UP_EXP_FOR_FLICKER) {
2787                /* exposure is now high enough to switch
2788                   flicker control back on */
2789                set_flicker(&cam->params, &cam->cmd_queue, 1);
2790                if((cam->cmd_queue & COMMAND_SETEXPOSURE) &&
2791                   cam->params.exposure.expMode == 2)
2792                        cam->exposure_status = EXPOSURE_NORMAL;
2793
2794        }
2795        mutex_unlock(&cam->param_lock);
2796}
2797#undef FIRMWARE_VERSION
2798
2799static int clear_stall(struct cam_data *cam)
2800{
2801        /* FIXME: Does this actually work? */
2802        LOG("Clearing stall\n");
2803
2804        cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
2805        do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2806        return cam->params.status.streamState != STREAM_PAUSED;
2807}
2808
2809/* kernel thread function to read image from camera */
2810static int fetch_frame(void *data)
2811{
2812        int image_size, retry;
2813        struct cam_data *cam = (struct cam_data *)data;
2814        unsigned long oldjif, rate, diff;
2815
2816        /* Allow up to two bad images in a row to be read and
2817         * ignored before an error is reported */
2818        for (retry = 0; retry < 3; ++retry) {
2819                if (retry)
2820                        DBG("retry=%d\n", retry);
2821
2822                if (!cam->ops)
2823                        continue;
2824
2825                /* load first frame always uncompressed */
2826                if (cam->first_frame &&
2827                    cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2828                        do_command(cam, CPIA_COMMAND_SetCompression,
2829                                   CPIA_COMPRESSION_NONE,
2830                                   NO_DECIMATION, 0, 0);
2831                        /* Trial & error - Discarding a frame prevents the
2832                           first frame from having an error in the data. */
2833                        do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2834                }
2835
2836                /* init camera upload */
2837                if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2838                               cam->params.streamStartLine, 0, 0))
2839                        continue;
2840
2841                if (cam->ops->wait_for_stream_ready) {
2842                        /* loop until image ready */
2843                        int count = 0;
2844                        do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2845                        while (cam->params.status.streamState != STREAM_READY) {
2846                                if(++count > READY_TIMEOUT)
2847                                        break;
2848                                if(cam->params.status.streamState ==
2849                                   STREAM_PAUSED) {
2850                                        /* Bad news */
2851                                        if(!clear_stall(cam))
2852                                                return -EIO;
2853                                }
2854
2855                                cond_resched();
2856
2857                                /* sleep for 10 ms, hopefully ;) */
2858                                msleep_interruptible(10);
2859                                if (signal_pending(current))
2860                                        return -EINTR;
2861
2862                                do_command(cam, CPIA_COMMAND_GetCameraStatus,
2863                                           0, 0, 0, 0);
2864                        }
2865                        if(cam->params.status.streamState != STREAM_READY) {
2866                                continue;
2867                        }
2868                }
2869
2870                cond_resched();
2871
2872                /* grab image from camera */
2873                oldjif = jiffies;
2874                image_size = cam->ops->streamRead(cam->lowlevel_data,
2875                                                  cam->raw_image, 0);
2876                if (image_size <= 0) {
2877                        DBG("streamRead failed: %d\n", image_size);
2878                        continue;
2879                }
2880
2881                rate = image_size * HZ / 1024;
2882                diff = jiffies-oldjif;
2883                cam->transfer_rate = diff==0 ? rate : rate/diff;
2884                        /* diff==0 ? unlikely but possible */
2885
2886                /* Switch flicker control back on if it got turned off */
2887                restart_flicker(cam);
2888
2889                /* If AEC is enabled, monitor the exposure and
2890                   adjust the sensor frame rate if needed */
2891                if(cam->params.exposure.expMode == 2)
2892                        monitor_exposure(cam);
2893
2894                /* camera idle now so dispatch queued commands */
2895                dispatch_commands(cam);
2896
2897                /* Update our knowledge of the camera state */
2898                do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2899                do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2900                do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
2901
2902                /* decompress and convert image to by copying it from
2903                 * raw_image to decompressed_frame
2904                 */
2905
2906                cond_resched();
2907
2908                cam->image_size = parse_picture(cam, image_size);
2909                if (cam->image_size <= 0) {
2910                        DBG("parse_picture failed %d\n", cam->image_size);
2911                        if(cam->params.compression.mode !=
2912                           CPIA_COMPRESSION_NONE) {
2913                                /* Compression may not work right if we
2914                                   had a bad frame, get the next one
2915                                   uncompressed. */
2916                                cam->first_frame = 1;
2917                                do_command(cam, CPIA_COMMAND_SetGrabMode,
2918                                           CPIA_GRAB_SINGLE, 0, 0, 0);
2919                                /* FIXME: Trial & error - need up to 70ms for
2920                                   the grab mode change to complete ? */
2921                                msleep_interruptible(70);
2922                                if (signal_pending(current))
2923                                        return -EINTR;
2924                        }
2925                } else
2926                        break;
2927        }
2928
2929        if (retry < 3) {
2930                /* FIXME: this only works for double buffering */
2931                if (cam->frame[cam->curframe].state == FRAME_READY) {
2932                        memcpy(cam->frame[cam->curframe].data,
2933                               cam->decompressed_frame.data,
2934                               cam->decompressed_frame.count);
2935                        cam->frame[cam->curframe].state = FRAME_DONE;
2936                } else
2937                        cam->decompressed_frame.state = FRAME_DONE;
2938
2939                if (cam->first_frame) {
2940                        cam->first_frame = 0;
2941                        do_command(cam, CPIA_COMMAND_SetCompression,
2942                                   cam->params.compression.mode,
2943                                   cam->params.compression.decimation, 0, 0);
2944
2945                        /* Switch from single-grab to continuous grab */
2946                        do_command(cam, CPIA_COMMAND_SetGrabMode,
2947                                   CPIA_GRAB_CONTINUOUS, 0, 0, 0);
2948                }
2949                return 0;
2950        }
2951        return -EIO;
2952}
2953
2954static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2955{
2956        if (!cam->frame_buf) {
2957                /* we do lazy allocation */
2958                int err;
2959                if ((err = allocate_frame_buf(cam)))
2960                        return err;
2961        }
2962
2963        cam->curframe = vm->frame;
2964        cam->frame[cam->curframe].state = FRAME_READY;
2965        return fetch_frame(cam);
2966}
2967
2968static int goto_high_power(struct cam_data *cam)
2969{
2970        if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2971                return -EIO;
2972        msleep_interruptible(40);        /* windows driver does it too */
2973        if(signal_pending(current))
2974                return -EINTR;
2975        if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2976                return -EIO;
2977        if (cam->params.status.systemState == HI_POWER_STATE) {
2978                DBG("camera now in HIGH power state\n");
2979                return 0;
2980        }
2981        printstatus(cam);
2982        return -EIO;
2983}
2984
2985static int goto_low_power(struct cam_data *cam)
2986{
2987        if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2988                return -1;
2989        if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2990                return -1;
2991        if (cam->params.status.systemState == LO_POWER_STATE) {
2992                DBG("camera now in LOW power state\n");
2993                return 0;
2994        }
2995        printstatus(cam);
2996        return -1;
2997}
2998
2999static void save_camera_state(struct cam_data *cam)
3000{
3001        if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE))
3002                do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
3003        if(!(cam->cmd_queue & COMMAND_SETEXPOSURE))
3004                do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
3005
3006        DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
3007             cam->params.exposure.gain,
3008             cam->params.exposure.fineExp,
3009             cam->params.exposure.coarseExpLo,
3010             cam->params.exposure.coarseExpHi,
3011             cam->params.exposure.redComp,
3012             cam->params.exposure.green1Comp,
3013             cam->params.exposure.green2Comp,
3014             cam->params.exposure.blueComp);
3015        DBG("%d/%d/%d\n",
3016             cam->params.colourBalance.redGain,
3017             cam->params.colourBalance.greenGain,
3018             cam->params.colourBalance.blueGain);
3019}
3020
3021static int set_camera_state(struct cam_data *cam)
3022{
3023        cam->cmd_queue = COMMAND_SETCOMPRESSION |
3024                         COMMAND_SETCOMPRESSIONTARGET |
3025                         COMMAND_SETCOLOURPARAMS |
3026                         COMMAND_SETFORMAT |
3027                         COMMAND_SETYUVTHRESH |
3028                         COMMAND_SETECPTIMING |
3029                         COMMAND_SETCOMPRESSIONPARAMS |
3030                         COMMAND_SETEXPOSURE |
3031                         COMMAND_SETCOLOURBALANCE |
3032                         COMMAND_SETSENSORFPS |
3033                         COMMAND_SETAPCOR |
3034                         COMMAND_SETFLICKERCTRL |
3035                         COMMAND_SETVLOFFSET;
3036
3037        do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
3038        dispatch_commands(cam);
3039
3040        /* Wait 6 frames for the sensor to get all settings and
3041           AEC/ACB to settle */
3042        msleep_interruptible(6*(cam->params.sensorFps.baserate ? 33 : 40) *
3043                               (1 << cam->params.sensorFps.divisor) + 10);
3044
3045        if(signal_pending(current))
3046                return -EINTR;
3047
3048        save_camera_state(cam);
3049
3050        return 0;
3051}
3052
3053static void get_version_information(struct cam_data *cam)
3054{
3055        /* GetCPIAVersion */
3056        do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
3057
3058        /* GetPnPID */
3059        do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
3060}
3061
3062/* initialize camera */
3063static int reset_camera(struct cam_data *cam)
3064{
3065        int err;
3066        /* Start the camera in low power mode */
3067        if (goto_low_power(cam)) {
3068                if (cam->params.status.systemState != WARM_BOOT_STATE)
3069                        return -ENODEV;
3070
3071                /* FIXME: this is just dirty trial and error */
3072                err = goto_high_power(cam);
3073                if(err)
3074                        return err;
3075                do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
3076                if (goto_low_power(cam))
3077                        return -ENODEV;
3078        }
3079
3080        /* procedure described in developer's guide p3-28 */
3081
3082        /* Check the firmware version. */
3083        cam->params.version.firmwareVersion = 0;
3084        get_version_information(cam);
3085        if (cam->params.version.firmwareVersion != 1)
3086                return -ENODEV;
3087
3088        /* A bug in firmware 1-02 limits gainMode to 2 */
3089        if(cam->params.version.firmwareRevision <= 2 &&
3090           cam->params.exposure.gainMode > 2) {
3091                cam->params.exposure.gainMode = 2;
3092        }
3093
3094        /* set QX3 detected flag */
3095        cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
3096                                        cam->params.pnpID.product == 0x0001);
3097
3098        /* The fatal error checking should be done after
3099         * the camera powers up (developer's guide p 3-38) */
3100
3101        /* Set streamState before transition to high power to avoid bug
3102         * in firmware 1-02 */
3103        do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
3104                   STREAM_NOT_READY, 0);
3105
3106        /* GotoHiPower */
3107        err = goto_high_power(cam);
3108        if (err)
3109                return err;
3110
3111        /* Check the camera status */
3112        if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3113                return -EIO;
3114
3115        if (cam->params.status.fatalError) {
3116                DBG("fatal_error:              %#04x\n",
3117                    cam->params.status.fatalError);
3118                DBG("vp_status:                %#04x\n",
3119                    cam->params.status.vpStatus);
3120                if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
3121                        /* Fatal error in camera */
3122                        return -EIO;
3123                } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
3124                        /* Firmware 1-02 may do this for parallel port cameras,
3125                         * just clear the flags (developer's guide p 3-38) */
3126                        do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
3127                                   FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
3128                }
3129        }
3130
3131        /* Check the camera status again */
3132        if (cam->params.status.fatalError) {
3133                if (cam->params.status.fatalError)
3134                        return -EIO;
3135        }
3136
3137        /* VPVersion can't be retrieved before the camera is in HiPower,
3138         * so get it here instead of in get_version_information. */
3139        do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
3140
3141        /* set camera to a known state */
3142        return set_camera_state(cam);
3143}
3144
3145static void put_cam(struct cpia_camera_ops* ops)
3146{
3147        module_put(ops->owner);
3148}
3149
3150/* ------------------------- V4L interface --------------------- */
3151static int cpia_open(struct inode *inode, struct file *file)
3152{
3153        struct video_device *dev = video_devdata(file);
3154        struct cam_data *cam = video_get_drvdata(dev);
3155        int err;
3156
3157        if (!cam) {
3158                DBG("Internal error, cam_data not found!\n");
3159                return -ENODEV;
3160        }
3161
3162        if (cam->open_count > 0) {
3163                DBG("Camera already open\n");
3164                return -EBUSY;
3165        }
3166
3167        if (!try_module_get(cam->ops->owner))
3168                return -ENODEV;
3169
3170        mutex_lock(&cam->busy_lock);
3171        err = -ENOMEM;
3172        if (!cam->raw_image) {
3173                cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
3174                if (!cam->raw_image)
3175                        goto oops;
3176        }
3177
3178        if (!cam->decompressed_frame.data) {
3179                cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
3180                if (!cam->decompressed_frame.data)
3181                        goto oops;
3182        }
3183
3184        /* open cpia */
3185        err = -ENODEV;
3186        if (cam->ops->open(cam->lowlevel_data))
3187                goto oops;
3188
3189        /* reset the camera */
3190        if ((err = reset_camera(cam)) != 0) {
3191                cam->ops->close(cam->lowlevel_data);
3192                goto oops;
3193        }
3194
3195        err = -EINTR;
3196        if(signal_pending(current))
3197                goto oops;
3198
3199        /* Set ownership of /proc/cpia/videoX to current user */
3200        if(cam->proc_entry)
3201                cam->proc_entry->uid = current_uid();
3202
3203        /* set mark for loading first frame uncompressed */
3204        cam->first_frame = 1;
3205
3206        /* init it to something */
3207        cam->mmap_kludge = 0;
3208
3209        ++cam->open_count;
3210        file->private_data = dev;
3211        mutex_unlock(&cam->busy_lock);
3212        return 0;
3213
3214 oops:
3215        if (cam->decompressed_frame.data) {
3216                rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3217                cam->decompressed_frame.data = NULL;
3218        }
3219        if (cam->raw_image) {
3220                rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3221                cam->raw_image = NULL;
3222        }
3223        mutex_unlock(&cam->busy_lock);
3224        put_cam(cam->ops);
3225        return err;
3226}
3227
3228static int cpia_close(struct inode *inode, struct file *file)
3229{
3230        struct  video_device *dev = file->private_data;
3231        struct cam_data *cam = video_get_drvdata(dev);
3232
3233        if (cam->ops) {
3234                /* Return ownership of /proc/cpia/videoX to root */
3235                if(cam->proc_entry)
3236                        cam->proc_entry->uid = 0;
3237
3238                /* save camera state for later open (developers guide ch 3.5.3) */
3239                save_camera_state(cam);
3240
3241                /* GotoLoPower */
3242                goto_low_power(cam);
3243
3244                /* Update the camera status */
3245                do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
3246
3247                /* cleanup internal state stuff */
3248                free_frames(cam->frame);
3249
3250                /* close cpia */
3251                cam->ops->close(cam->lowlevel_data);
3252
3253                put_cam(cam->ops);
3254        }
3255
3256        if (--cam->open_count == 0) {
3257                /* clean up capture-buffers */
3258                if (cam->raw_image) {
3259                        rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3260                        cam->raw_image = NULL;
3261                }
3262
3263                if (cam->decompressed_frame.data) {
3264                        rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3265                        cam->decompressed_frame.data = NULL;
3266                }
3267
3268                if (cam->frame_buf)
3269                        free_frame_buf(cam);
3270
3271                if (!cam->ops)
3272                        kfree(cam);
3273        }
3274        file->private_data = NULL;
3275
3276        return 0;
3277}
3278
3279static ssize_t cpia_read(struct file *file, char __user *buf,
3280                         size_t count, loff_t *ppos)
3281{
3282        struct video_device *dev = file->private_data;
3283        struct cam_data *cam = video_get_drvdata(dev);
3284        int err;
3285
3286        /* make this _really_ smp and multithread-safe */
3287        if (mutex_lock_interruptible(&cam->busy_lock))
3288                return -EINTR;
3289
3290        if (!buf) {
3291                DBG("buf NULL\n");
3292                mutex_unlock(&cam->busy_lock);
3293                return -EINVAL;
3294        }
3295
3296        if (!count) {
3297                DBG("count 0\n");
3298                mutex_unlock(&cam->busy_lock);
3299                return 0;
3300        }
3301
3302        if (!cam->ops) {
3303                DBG("ops NULL\n");
3304                mutex_unlock(&cam->busy_lock);
3305                return -ENODEV;
3306        }
3307
3308        /* upload frame */
3309        cam->decompressed_frame.state = FRAME_READY;
3310        cam->mmap_kludge=0;
3311        if((err = fetch_frame(cam)) != 0) {
3312                DBG("ERROR from fetch_frame: %d\n", err);
3313                mutex_unlock(&cam->busy_lock);
3314                return err;
3315        }
3316        cam->decompressed_frame.state = FRAME_UNUSED;
3317
3318        /* copy data to user space */
3319        if (cam->decompressed_frame.count > count) {
3320                DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
3321                    (unsigned long) count);
3322                mutex_unlock(&cam->busy_lock);
3323                return -EFAULT;
3324        }
3325        if (copy_to_user(buf, cam->decompressed_frame.data,
3326                        cam->decompressed_frame.count)) {
3327                DBG("copy_to_user failed\n");
3328                mutex_unlock(&cam->busy_lock);
3329                return -EFAULT;
3330        }
3331
3332        mutex_unlock(&cam->busy_lock);
3333        return cam->decompressed_frame.count;
3334}
3335
3336static int cpia_do_ioctl(struct inode *inode, struct file *file,
3337                         unsigned int ioctlnr, void *arg)
3338{
3339        struct video_device *dev = file->private_data;
3340        struct cam_data *cam = video_get_drvdata(dev);
3341        int retval = 0;
3342
3343        if (!cam || !cam->ops)
3344                return -ENODEV;
3345
3346        /* make this _really_ smp-safe */
3347        if (mutex_lock_interruptible(&cam->busy_lock))
3348                return -EINTR;
3349
3350        //DBG("cpia_ioctl: %u\n", ioctlnr);
3351
3352        switch (ioctlnr) {
3353        /* query capabilities */
3354        case VIDIOCGCAP:
3355        {
3356                struct video_capability *b = arg;
3357
3358                DBG("VIDIOCGCAP\n");
3359                strcpy(b->name, "CPiA Camera");
3360                b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
3361                b->channels = 1;
3362                b->audios = 0;
3363                b->maxwidth = 352;        /* VIDEOSIZE_CIF */
3364                b->maxheight = 288;
3365                b->minwidth = 48;        /* VIDEOSIZE_48_48 */
3366                b->minheight = 48;
3367                break;
3368        }
3369
3370        /* get/set video source - we are a camera and nothing else */
3371        case VIDIOCGCHAN:
3372        {
3373                struct video_channel *v = arg;
3374
3375                DBG("VIDIOCGCHAN\n");
3376                if (v->channel != 0) {
3377                        retval = -EINVAL;
3378                        break;
3379                }
3380
3381                v->channel = 0;
3382                strcpy(v->name, "Camera");
3383                v->tuners = 0;
3384                v->flags = 0;
3385                v->type = VIDEO_TYPE_CAMERA;
3386                v->norm = 0;
3387                break;
3388        }
3389
3390        case VIDIOCSCHAN:
3391        {
3392                struct video_channel *v = arg;
3393
3394                DBG("VIDIOCSCHAN\n");
3395                if (v->channel != 0)
3396                        retval = -EINVAL;
3397                break;
3398        }
3399
3400        /* image properties */
3401        case VIDIOCGPICT:
3402        {
3403                struct video_picture *pic = arg;
3404                DBG("VIDIOCGPICT\n");
3405                *pic = cam->vp;
3406                break;
3407        }
3408
3409        case VIDIOCSPICT:
3410        {
3411                struct video_picture *vp = arg;
3412
3413                DBG("VIDIOCSPICT\n");
3414
3415                /* check validity */
3416                DBG("palette: %d\n", vp->palette);
3417                DBG("depth: %d\n", vp->depth);
3418                if (!valid_mode(vp->palette, vp->depth)) {
3419                        retval = -EINVAL;
3420                        break;
3421                }
3422
3423                mutex_lock(&cam->param_lock);
3424                /* brightness, colour, contrast need no check 0-65535 */
3425                cam->vp = *vp;
3426                /* update cam->params.colourParams */
3427                cam->params.colourParams.brightness = vp->brightness*100/65535;
3428                cam->params.colourParams.contrast = vp->contrast*100/65535;
3429                cam->params.colourParams.saturation = vp->colour*100/65535;
3430                /* contrast is in steps of 8, so round */
3431                cam->params.colourParams.contrast =
3432                        ((cam->params.colourParams.contrast + 3) / 8) * 8;
3433                if (cam->params.version.firmwareVersion == 1 &&
3434                    cam->params.version.firmwareRevision == 2 &&
3435                    cam->params.colourParams.contrast > 80) {
3436                        /* 1-02 firmware limits contrast to 80 */
3437                        cam->params.colourParams.contrast = 80;
3438                }
3439
3440                /* Adjust flicker control if necessary */
3441                if(cam->params.flickerControl.allowableOverExposure < 0)
3442                        cam->params.flickerControl.allowableOverExposure =
3443                                -find_over_exposure(cam->params.colourParams.brightness);
3444                if(cam->params.flickerControl.flickerMode != 0)
3445                        cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
3446
3447
3448                /* queue command to update camera */
3449                cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
3450                mutex_unlock(&cam->param_lock);
3451                DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
3452                    vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
3453                    vp->contrast);
3454                break;
3455        }
3456
3457        /* get/set capture window */
3458        case VIDIOCGWIN:
3459        {
3460                struct video_window *vw = arg;
3461                DBG("VIDIOCGWIN\n");
3462
3463                *vw = cam->vw;
3464                break;
3465        }
3466
3467        case VIDIOCSWIN:
3468        {
3469                /* copy_from_user, check validity, copy to internal structure */
3470                struct video_window *vw = arg;
3471                DBG("VIDIOCSWIN\n");
3472
3473                if (vw->clipcount != 0) {    /* clipping not supported */
3474                        retval = -EINVAL;
3475                        break;
3476                }
3477                if (vw->clips != NULL) {     /* clipping not supported */
3478                        retval = -EINVAL;
3479                        break;
3480                }
3481
3482                /* we set the video window to something smaller or equal to what
3483                * is requested by the user???
3484                */
3485                mutex_lock(&cam->param_lock);
3486                if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
3487                        int video_size = match_videosize(vw->width, vw->height);
3488
3489                        if (video_size < 0) {
3490                                retval = -EINVAL;
3491                                mutex_unlock(&cam->param_lock);
3492                                break;
3493                        }
3494                        cam->video_size = video_size;
3495
3496                        /* video size is changing, reset the subcapture area */
3497                        memset(&cam->vc, 0, sizeof(cam->vc));
3498
3499                        set_vw_size(cam);
3500                        DBG("%d / %d\n", cam->vw.width, cam->vw.height);
3501                        cam->cmd_queue |= COMMAND_SETFORMAT;
3502                }
3503
3504                mutex_unlock(&cam->param_lock);
3505
3506                /* setformat ignored by camera during streaming,
3507                 * so stop/dispatch/start */
3508                if (cam->cmd_queue & COMMAND_SETFORMAT) {
3509                        DBG("\n");
3510                        dispatch_commands(cam);
3511                }
3512                DBG("%d/%d:%d\n", cam->video_size,
3513                    cam->vw.width, cam->vw.height);
3514                break;
3515        }
3516
3517        /* mmap interface */
3518        case VIDIOCGMBUF:
3519        {
3520                struct video_mbuf *vm = arg;
3521                int i;
3522
3523                DBG("VIDIOCGMBUF\n");
3524                memset(vm, 0, sizeof(*vm));
3525                vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
3526                vm->frames = FRAME_NUM;
3527                for (i = 0; i < FRAME_NUM; i++)
3528                        vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
3529                break;
3530        }
3531
3532        case VIDIOCMCAPTURE:
3533        {
3534                struct video_mmap *vm = arg;
3535                int video_size;
3536
3537                DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
3538                    vm->width, vm->height);
3539                if (vm->frame<0||vm->frame>=FRAME_NUM) {
3540                        retval = -EINVAL;
3541                        break;
3542                }
3543
3544                /* set video format */
3545                cam->vp.palette = vm->format;
3546                switch(vm->format) {
3547                case VIDEO_PALETTE_GREY:
3548                        cam->vp.depth=8;
3549                        break;
3550                case VIDEO_PALETTE_RGB555:
3551                case VIDEO_PALETTE_RGB565:
3552                case VIDEO_PALETTE_YUV422:
3553                case VIDEO_PALETTE_YUYV:
3554                case VIDEO_PALETTE_UYVY:
3555                        cam->vp.depth = 16;
3556                        break;
3557                case VIDEO_PALETTE_RGB24:
3558                        cam->vp.depth = 24;
3559                        break;
3560                case VIDEO_PALETTE_RGB32:
3561                        cam->vp.depth = 32;
3562                        break;
3563                default:
3564                        retval = -EINVAL;
3565                        break;
3566                }
3567                if (retval)
3568                        break;
3569
3570                /* set video size */
3571                video_size = match_videosize(vm->width, vm->height);
3572                if (video_size < 0) {
3573                        retval = -EINVAL;
3574                        break;
3575                }
3576                if (video_size != cam->video_size) {
3577                        cam->video_size = video_size;
3578
3579                        /* video size is changing, reset the subcapture area */
3580                        memset(&cam->vc, 0, sizeof(cam->vc));
3581
3582                        set_vw_size(cam);
3583                        cam->cmd_queue |= COMMAND_SETFORMAT;
3584                        dispatch_commands(cam);
3585                }
3586                /* according to v4l-spec we must start streaming here */
3587                cam->mmap_kludge = 1;
3588                retval = capture_frame(cam, vm);
3589
3590                break;
3591        }
3592
3593        case VIDIOCSYNC:
3594        {
3595                int *frame = arg;
3596
3597                //DBG("VIDIOCSYNC: %d\n", *frame);
3598
3599                if (*frame<0 || *frame >= FRAME_NUM) {
3600                        retval = -EINVAL;
3601                        break;
3602                }
3603
3604                switch (cam->frame[*frame].state) {
3605                case FRAME_UNUSED:
3606                case FRAME_READY:
3607                case FRAME_GRABBING:
3608                        DBG("sync to unused frame %d\n", *frame);
3609                        retval = -EINVAL;
3610                        break;
3611
3612                case FRAME_DONE:
3613                        cam->frame[*frame].state = FRAME_UNUSED;
3614                        //DBG("VIDIOCSYNC: %d synced\n", *frame);
3615                        break;
3616                }
3617                if (retval == -EINTR) {
3618                        /* FIXME - xawtv does not handle this nice */
3619                        retval = 0;
3620                }
3621                break;
3622        }
3623
3624        case VIDIOCGCAPTURE:
3625        {
3626                struct video_capture *vc = arg;
3627
3628                DBG("VIDIOCGCAPTURE\n");
3629
3630                *vc = cam->vc;
3631
3632                break;
3633        }
3634
3635        case VIDIOCSCAPTURE:
3636        {
3637                struct video_capture *vc = arg;
3638
3639                DBG("VIDIOCSCAPTURE\n");
3640
3641                if (vc->decimation != 0) {    /* How should this be used? */
3642                        retval = -EINVAL;
3643                        break;
3644                }
3645                if (vc->flags != 0) {     /* Even/odd grab not supported */
3646                        retval = -EINVAL;
3647                        break;
3648                }
3649
3650                /* Clip to the resolution we can set for the ROI
3651                   (every 8 columns and 4 rows) */
3652                vc->x      = vc->x      & ~(__u32)7;
3653                vc->y      = vc->y      & ~(__u32)3;
3654                vc->width  = vc->width  & ~(__u32)7;
3655                vc->height = vc->height & ~(__u32)3;
3656
3657                if(vc->width == 0 || vc->height == 0 ||
3658                   vc->x + vc->width  > cam->vw.width ||
3659                   vc->y + vc->height > cam->vw.height) {
3660                        retval = -EINVAL;
3661                        break;
3662                }
3663
3664                DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
3665
3666                mutex_lock(&cam->param_lock);
3667
3668                cam->vc.x      = vc->x;
3669                cam->vc.y      = vc->y;
3670                cam->vc.width  = vc->width;
3671                cam->vc.height = vc->height;
3672
3673                set_vw_size(cam);
3674                cam->cmd_queue |= COMMAND_SETFORMAT;
3675
3676                mutex_unlock(&cam->param_lock);
3677
3678                /* setformat ignored by camera during streaming,
3679                 * so stop/dispatch/start */
3680                dispatch_commands(cam);
3681                break;
3682        }
3683
3684        case VIDIOCGUNIT:
3685        {
3686                struct video_unit *vu = arg;
3687
3688                DBG("VIDIOCGUNIT\n");
3689
3690                vu->video    = cam->vdev.minor;
3691                vu->vbi      = VIDEO_NO_UNIT;
3692                vu->radio    = VIDEO_NO_UNIT;
3693                vu->audio    = VIDEO_NO_UNIT;
3694                vu->teletext = VIDEO_NO_UNIT;
3695
3696                break;
3697        }
3698
3699
3700        /* pointless to implement overlay with this camera */
3701        case VIDIOCCAPTURE:
3702        case VIDIOCGFBUF:
3703        case VIDIOCSFBUF:
3704        case VIDIOCKEY:
3705        /* tuner interface - we have none */
3706        case VIDIOCGTUNER:
3707        case VIDIOCSTUNER:
3708        case VIDIOCGFREQ:
3709        case VIDIOCSFREQ:
3710        /* audio interface - we have none */
3711        case VIDIOCGAUDIO:
3712        case VIDIOCSAUDIO:
3713                retval = -EINVAL;
3714                break;
3715        default:
3716                retval = -ENOIOCTLCMD;
3717                break;
3718        }
3719
3720        mutex_unlock(&cam->busy_lock);
3721        return retval;
3722}
3723
3724static int cpia_ioctl(struct inode *inode, struct file *file,
3725                     unsigned int cmd, unsigned long arg)
3726{
3727        return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
3728}
3729
3730
3731/* FIXME */
3732static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
3733{
3734        struct video_device *dev = file->private_data;
3735        unsigned long start = vma->vm_start;
3736        unsigned long size  = vma->vm_end - vma->vm_start;
3737        unsigned long page, pos;
3738        struct cam_data *cam = video_get_drvdata(dev);
3739        int retval;
3740
3741        if (!cam || !cam->ops)
3742                return -ENODEV;
3743
3744        DBG("cpia_mmap: %ld\n", size);
3745
3746        if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
3747                return -EINVAL;
3748
3749        if (!cam || !cam->ops)
3750                return -ENODEV;
3751
3752        /* make this _really_ smp-safe */
3753        if (mutex_lock_interruptible(&cam->busy_lock))
3754                return -EINTR;
3755
3756        if (!cam->frame_buf) {        /* we do lazy allocation */
3757                if ((retval = allocate_frame_buf(cam))) {
3758                        mutex_unlock(&cam->busy_lock);
3759                        return retval;
3760                }
3761        }
3762
3763        pos = (unsigned long)(cam->frame_buf);
3764        while (size > 0) {
3765                page = vmalloc_to_pfn((void *)pos);
3766                if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
3767                        mutex_unlock(&cam->busy_lock);
3768                        return -EAGAIN;
3769                }
3770                start += PAGE_SIZE;
3771                pos += PAGE_SIZE;
3772                if (size > PAGE_SIZE)
3773                        size -= PAGE_SIZE;
3774                else
3775                        size = 0;
3776        }
3777
3778        DBG("cpia_mmap: %ld\n", size);
3779        mutex_unlock(&cam->busy_lock);
3780
3781        return 0;
3782}
3783
3784static const struct file_operations cpia_fops = {
3785        .owner                = THIS_MODULE,
3786        .open                = cpia_open,
3787        .release               = cpia_close,
3788        .read                = cpia_read,
3789        .mmap                = cpia_mmap,
3790        .ioctl          = cpia_ioctl,
3791#ifdef CONFIG_COMPAT
3792        .compat_ioctl        = v4l_compat_ioctl32,
3793#endif
3794        .llseek         = no_llseek,
3795};
3796
3797static struct video_device cpia_template = {
3798        .name                = "CPiA Camera",
3799        .fops           = &cpia_fops,
3800        .release         = video_device_release_empty,
3801};
3802
3803/* initialise cam_data structure  */
3804static void reset_camera_struct(struct cam_data *cam)
3805{
3806        /* The following parameter values are the defaults from
3807         * "Software Developer's Guide for CPiA Cameras".  Any changes
3808         * to the defaults are noted in comments. */
3809        cam->params.colourParams.brightness = 50;
3810        cam->params.colourParams.contrast = 48;
3811        cam->params.colourParams.saturation = 50;
3812        cam->params.exposure.gainMode = 4;
3813        cam->params.exposure.expMode = 2;                /* AEC */
3814        cam->params.exposure.compMode = 1;
3815        cam->params.exposure.centreWeight = 1;
3816        cam->params.exposure.gain = 0;
3817        cam->params.exposure.fineExp = 0;
3818        cam->params.exposure.coarseExpLo = 185;
3819        cam->params.exposure.coarseExpHi = 0;
3820        cam->params.exposure.redComp = COMP_RED;
3821        cam->params.exposure.green1Comp = COMP_GREEN1;
3822        cam->params.exposure.green2Comp = COMP_GREEN2;
3823        cam->params.exposure.blueComp = COMP_BLUE;
3824        cam->params.colourBalance.balanceMode = 2;        /* ACB */
3825        cam->params.colourBalance.redGain = 32;
3826        cam->params.colourBalance.greenGain = 6;
3827        cam->params.colourBalance.blueGain = 92;
3828        cam->params.apcor.gain1 = 0x18;
3829        cam->params.apcor.gain2 = 0x16;
3830        cam->params.apcor.gain4 = 0x24;
3831        cam->params.apcor.gain8 = 0x34;
3832        cam->params.flickerControl.flickerMode = 0;
3833        cam->params.flickerControl.disabled = 1;
3834
3835        cam->params.flickerControl.coarseJump =
3836                flicker_jumps[cam->mainsFreq]
3837                             [cam->params.sensorFps.baserate]
3838                             [cam->params.sensorFps.divisor];
3839        cam->params.flickerControl.allowableOverExposure =
3840                -find_over_exposure(cam->params.colourParams.brightness);
3841        cam->params.vlOffset.gain1 = 20;
3842        cam->params.vlOffset.gain2 = 24;
3843        cam->params.vlOffset.gain4 = 26;
3844        cam->params.vlOffset.gain8 = 26;
3845        cam->params.compressionParams.hysteresis = 3;
3846        cam->params.compressionParams.threshMax = 11;
3847        cam->params.compressionParams.smallStep = 1;
3848        cam->params.compressionParams.largeStep = 3;
3849        cam->params.compressionParams.decimationHysteresis = 2;
3850        cam->params.compressionParams.frDiffStepThresh = 5;
3851        cam->params.compressionParams.qDiffStepThresh = 3;
3852        cam->params.compressionParams.decimationThreshMod = 2;
3853        /* End of default values from Software Developer's Guide */
3854
3855        cam->transfer_rate = 0;
3856        cam->exposure_status = EXPOSURE_NORMAL;
3857
3858        /* Set Sensor FPS to 15fps. This seems better than 30fps
3859         * for indoor lighting. */
3860        cam->params.sensorFps.divisor = 1;
3861        cam->params.sensorFps.baserate = 1;
3862
3863        cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
3864        cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
3865
3866        cam->params.format.subSample = SUBSAMPLE_422;
3867        cam->params.format.yuvOrder = YUVORDER_YUYV;
3868
3869        cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3870        cam->params.compressionTarget.frTargeting =
3871                CPIA_COMPRESSION_TARGET_QUALITY;
3872        cam->params.compressionTarget.targetFR = 15; /* From windows driver */
3873        cam->params.compressionTarget.targetQ = 5; /* From windows driver */
3874
3875        cam->params.qx3.qx3_detected = 0;
3876        cam->params.qx3.toplight = 0;
3877        cam->params.qx3.bottomlight = 0;
3878        cam->params.qx3.button = 0;
3879        cam->params.qx3.cradled = 0;
3880
3881        cam->video_size = VIDEOSIZE_CIF;
3882
3883        cam->vp.colour = 32768;      /* 50% */
3884        cam->vp.hue = 32768;         /* 50% */
3885        cam->vp.brightness = 32768;  /* 50% */
3886        cam->vp.contrast = 32768;    /* 50% */
3887        cam->vp.whiteness = 0;       /* not used -> grayscale only */
3888        cam->vp.depth = 24;          /* to be set by user */
3889        cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
3890
3891        cam->vc.x = 0;
3892        cam->vc.y = 0;
3893        cam->vc.width = 0;
3894        cam->vc.height = 0;
3895
3896        cam->vw.x = 0;
3897        cam->vw.y = 0;
3898        set_vw_size(cam);
3899        cam->vw.chromakey = 0;
3900        cam->vw.flags = 0;
3901        cam->vw.clipcount = 0;
3902        cam->vw.clips = NULL;
3903
3904        cam->cmd_queue = COMMAND_NONE;
3905        cam->first_frame = 1;
3906
3907        return;
3908}
3909
3910/* initialize cam_data structure  */
3911static void init_camera_struct(struct cam_data *cam,
3912                               struct cpia_camera_ops *ops )
3913{
3914        int i;
3915
3916        /* Default everything to 0 */
3917        memset(cam, 0, sizeof(struct cam_data));
3918
3919        cam->ops = ops;
3920        mutex_init(&cam->param_lock);
3921        mutex_init(&cam->busy_lock);
3922
3923        reset_camera_struct(cam);
3924
3925        cam->proc_entry = NULL;
3926
3927        memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3928        video_set_drvdata(&cam->vdev, cam);
3929
3930        cam->curframe = 0;
3931        for (i = 0; i < FRAME_NUM; i++) {
3932                cam->frame[i].width = 0;
3933                cam->frame[i].height = 0;
3934                cam->frame[i].state = FRAME_UNUSED;
3935                cam->frame[i].data = NULL;
3936        }
3937        cam->decompressed_frame.width = 0;
3938        cam->decompressed_frame.height = 0;
3939        cam->decompressed_frame.state = FRAME_UNUSED;
3940        cam->decompressed_frame.data = NULL;
3941}
3942
3943struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3944{
3945        struct cam_data *camera;
3946
3947        if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
3948                return NULL;
3949
3950
3951        init_camera_struct( camera, ops );
3952        camera->lowlevel_data = lowlevel;
3953
3954        /* register v4l device */
3955        if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
3956                kfree(camera);
3957                printk(KERN_DEBUG "video_register_device failed\n");
3958                return NULL;
3959        }
3960
3961        /* get version information from camera: open/reset/close */
3962
3963        /* open cpia */
3964        if (camera->ops->open(camera->lowlevel_data))
3965                return camera;
3966
3967        /* reset the camera */
3968        if (reset_camera(camera) != 0) {
3969                camera->ops->close(camera->lowlevel_data);
3970                return camera;
3971        }
3972
3973        /* close cpia */
3974        camera->ops->close(camera->lowlevel_data);
3975
3976#ifdef CONFIG_PROC_FS
3977        create_proc_cpia_cam(camera);
3978#endif
3979
3980        printk(KERN_INFO "  CPiA Version: %d.%02d (%d.%d)\n",
3981               camera->params.version.firmwareVersion,
3982               camera->params.version.firmwareRevision,
3983               camera->params.version.vcVersion,
3984               camera->params.version.vcRevision);
3985        printk(KERN_INFO "  CPiA PnP-ID: %04x:%04x:%04x\n",
3986               camera->params.pnpID.vendor,
3987               camera->params.pnpID.product,
3988               camera->params.pnpID.deviceRevision);
3989        printk(KERN_INFO "  VP-Version: %d.%d %04x\n",
3990               camera->params.vpVersion.vpVersion,
3991               camera->params.vpVersion.vpRevision,
3992               camera->params.vpVersion.cameraHeadID);
3993
3994        return camera;
3995}
3996
3997void cpia_unregister_camera(struct cam_data *cam)
3998{
3999        DBG("unregistering video\n");
4000        video_unregister_device(&cam->vdev);
4001        if (cam->open_count) {
4002                put_cam(cam->ops);
4003                DBG("camera open -- setting ops to NULL\n");
4004                cam->ops = NULL;
4005        }
4006
4007#ifdef CONFIG_PROC_FS
4008        DBG("destroying /proc/cpia/video%d\n", cam->vdev.num);
4009        destroy_proc_cpia_cam(cam);
4010#endif
4011        if (!cam->open_count) {
4012                DBG("freeing camera\n");
4013                kfree(cam);
4014        }
4015}
4016
4017static int __init cpia_init(void)
4018{
4019        printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
4020               CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
4021
4022        printk(KERN_WARNING "Since in-kernel colorspace conversion is not "
4023               "allowed, it is disabled by default now. Users should fix the "
4024               "applications in case they don't work without conversion "
4025               "reenabled by setting the 'colorspace_conv' module "
4026               "parameter to 1\n");
4027
4028#ifdef CONFIG_PROC_FS
4029        proc_cpia_create();
4030#endif
4031
4032        return 0;
4033}
4034
4035static void __exit cpia_exit(void)
4036{
4037#ifdef CONFIG_PROC_FS
4038        proc_cpia_destroy();
4039#endif
4040}
4041
4042module_init(cpia_init);
4043module_exit(cpia_exit);
4044
4045/* Exported symbols for modules. */
4046
4047EXPORT_SYMBOL(cpia_register_camera);
4048EXPORT_SYMBOL(cpia_unregister_camera);