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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [media/] [video/] [cpia.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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