OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [media/] [video/] [cpia.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.