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