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