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