~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/media/video/cpia.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.