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