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