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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
        Winbond w9966cf Webcam parport driver.
3
 
4
        Copyright (C) 2001 Jakob Kemi <jakob.kemi@telia.com>
5
 
6
        This program is free software; you can redistribute it and/or modify
7
        it under the terms of the GNU General Public License as published by
8
        the Free Software Foundation; either version 2 of the License, or
9
        (at your option) any later version.
10
 
11
        This program is distributed in the hope that it will be useful,
12
        but WITHOUT ANY WARRANTY; without even the implied warranty of
13
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
        GNU General Public License for more details.
15
 
16
        You should have received a copy of the GNU General Public License
17
        along with this program; if not, write to the Free Software
18
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
*/
20
/*
21
        Supported devices:
22
          * Lifeview Flycam Supra (Philips saa7111a chip)
23
 
24
          * Mikrotek Eyestar2 (Sanyo lc99053 chip)
25
            Very rudimentary support, total lack of ccd-control chip settings.
26
            Only green video data and no image properties (brightness, etc..)
27
            If anyone can parse the Japanese data-sheet for the Sanyo lc99053
28
            chip, feel free to help.
29
            <http://service.semic.sanyo.co.jp/semi/ds_pdf_j/LC99053.pdf>
30
            Thanks to Steven Griffiths <steve@sgriff.com> and
31
            James Murray <jsm@jsm-net.demon.co.uk> for testing.
32
 
33
        Todo:
34
          * Add a working EPP mode (Is this a parport or a w9966 issue?)
35
          * Add proper probing. IEEE1284 probing of w9966 chips haven't
36
            worked since parport drivers changed in 2.4.x.
37
          * Probe for onboard SRAM, port directions etc. (possible?)
38
 
39
        Changes:
40
 
41
        Alan Cox:       Removed RGB mode for kernel merge, added THIS_MODULE
42
                        and owner support for newer module locks
43
*/
44
 
45
#include <linux/module.h>
46
#include <linux/init.h>
47
#include <linux/delay.h>
48
#include <linux/videodev.h>
49
#include <linux/parport.h>
50
#include <linux/types.h>
51
#include <linux/slab.h>
52
 
53
//#define DEBUG                         // Define for debug output.
54
 
55
#ifdef DEBUG
56
#   define DPRINTF(f, a...)                                             \
57
        do {                                                            \
58
            printk ("%s%s, %d (DEBUG) %s(): ",                          \
59
                KERN_DEBUG, __FILE__, __LINE__, __func__);              \
60
            printk (f, ##a);                                            \
61
        } while (0)
62
#   define DASSERT(x)                                                   \
63
        do {                                                            \
64
            if (!x)                                                     \
65
                DPRINTF("Assertion failed at line %d.\n", __LINE__);    \
66
        } while (0)
67
#else
68
#   define DPRINTF(f, a...) do {} while(0)
69
#   define DASSERT(f, a...) do {} while(0)
70
#endif
71
 
72
/*
73
 *      Defines, simple typedefs etc.
74
 */
75
 
76
#define W9966_DRIVERNAME        "w9966cf"
77
#define W9966_MAXCAMS           4       // Maximum number of cameras
78
#define W9966_RBUFFER           8096    // Read buffer (must be an even number)
79
 
80
#define W9966_WND_MIN_W         2
81
#define W9966_WND_MIN_H         1
82
 
83
// Keep track of our current state
84
#define W9966_STATE_PDEV        0x01    // pdev registered
85
#define W9966_STATE_CLAIMED     0x02    // pdev claimed
86
#define W9966_STATE_VDEV        0x04    // vdev registered
87
#define W9966_STATE_BUFFER      0x08    // buffer allocated
88
#define W9966_STATE_DETECTED    0x10    // model identified
89
 
90
#define W9966_SAA7111_ID        0x24    // I2C device id
91
 
92
#define W9966_I2C_UDELAY        5
93
#define W9966_I2C_TIMEOUT       100
94
#define W9966_I2C_R_DATA        0x08
95
#define W9966_I2C_R_CLOCK       0x04
96
#define W9966_I2C_W_DATA        0x02
97
#define W9966_I2C_W_CLOCK       0x01
98
 
99
#define MAX(a, b) ((a > b) ? a : b)
100
#define MIN(a, b) ((a > b) ? b : a)
101
 
102
struct w9966_dev {
103
        struct video_device vdev;
104
        struct parport*     pport;
105
        struct pardevice*   pdev;
106
        int ppmode;
107
 
108
        u8* buffer;
109
        u8  dev_state;
110
        u8  i2c_state;
111
        u16 width;
112
        u16 height;
113
 
114
        // Image properties
115
        u8 brightness;
116
        s8 contrast;
117
        s8 color;
118
        s8 hue;
119
 
120
        // Model specific:
121
        const char* name;
122
        u32 sramsize;
123
        u8  sramid;             // reg 0x0c, bank layout
124
        u8  cmask;              // reg 0x01, for polarity
125
        u16 min_x, max_x;       // Capture window limits
126
        u16 min_y, max_y;
127
        int (*image)(struct w9966_dev* cam);
128
};
129
 
130
/*
131
 *      Module properties
132
 */
133
 
134
MODULE_AUTHOR("Jakob Kemi <jakob.kemi@telia.com>");
135
MODULE_DESCRIPTION("Winbond w9966cf webcam driver (Flycam Supra and others)");
136
MODULE_LICENSE("GPL");
137
 
138
 
139
static const char* pardev[] = {[0 ... W9966_MAXCAMS-1] = "auto"};
140
MODULE_PARM(pardev, "0-" __MODULE_STRING(W9966_MAXCAMS) "s");
141
MODULE_PARM_DESC(pardev,"\n\
142
<auto|name|none[,...]> Where to find cameras.\n\
143
  auto = probe all parports for camera (default)\n\
144
  name = name of parport (eg parport0)\n\
145
  none = don't use this camera\n\
146
You can specify all cameras this way, for example:\n\
147
  pardev=parport2,auto,none,parport0 would search for cam1 on parport2, search\n\
148
  for cam2 on all parports, skip cam3 and search for cam4 on parport0");
149
 
150
static int parmode = 1;
151
MODULE_PARM(parmode, "i");
152
MODULE_PARM_DESC(parmode, "\n<0|1|2|3> transfer mode (0=auto, 1=ecp(default), 2=epp, 3=forced hw-ecp)");
153
 
154
static int video_nr[] = {[0 ... W9966_MAXCAMS-1] = -1};
155
MODULE_PARM(video_nr, "0-" __MODULE_STRING(W9966_MAXCAMS) "i");
156
MODULE_PARM_DESC(video_nr,"\n\
157
<-1|n[,...]> Specify V4L minor mode number.\n\
158
  -1 = use next available (default)\n\
159
   n = use minor number n (integer >= 0)\n\
160
You can specify all cameras this way, for example:\n\
161
  video_nr=-1,2,-1 would assign minor number 2 for cam2 and use auto for cam1,\n\
162
  cam3 and cam4");
163
 
164
/*
165
 *      Private data
166
 */
167
 
168
static struct w9966_dev* w9966_cams;
169
 
170
/*
171
 *      Private function declarations
172
 */
173
 
174
static inline void w9966_flag_set(struct w9966_dev* cam, int flag) {
175
        cam->dev_state |= flag;}
176
 
177
static inline void w9966_flag_clear(struct w9966_dev* cam, int flag) {
178
        cam->dev_state &= ~flag;}
179
 
180
static inline int  w9966_flag_test(struct w9966_dev* cam, int flag) {
181
        return (cam->dev_state & flag);}
182
 
183
static inline int  w9966_pdev_claim(struct w9966_dev *vdev);
184
static inline void w9966_pdev_release(struct w9966_dev *vdev);
185
 
186
static int w9966_rreg(struct w9966_dev* cam, int reg);
187
static int w9966_wreg(struct w9966_dev* cam, int reg, int data);
188
 
189
static int  w9966_init(struct w9966_dev* cam, struct parport* port, int vidnr);
190
static void w9966_term(struct w9966_dev* cam);
191
static int  w9966_setup(struct w9966_dev* cam);
192
static int  w9966_findlen(int near, int size, int maxlen);
193
static int  w9966_calcscale(int size, int min, int max,
194
                        int* beg, int* end, u8* factor);
195
static int  w9966_window(struct w9966_dev* cam, int x1, int y1,
196
                        int x2, int y2, int w, int h);
197
 
198
static int w9966_saa7111_init(struct w9966_dev* cam);
199
static int w9966_saa7111_image(struct w9966_dev* cam);
200
static int w9966_lc99053_init(struct w9966_dev* cam);
201
static int w9966_lc99053_image(struct w9966_dev* cam);
202
 
203
static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state);
204
static inline int  w9966_i2c_setscl(struct w9966_dev* cam, int state);
205
static inline int  w9966_i2c_getsda(struct w9966_dev* cam);
206
static inline int  w9966_i2c_getscl(struct w9966_dev* cam);
207
static int w9966_i2c_wbyte(struct w9966_dev* cam, int data);
208
static int w9966_i2c_rbyte(struct w9966_dev* cam);
209
static int w9966_i2c_rreg(struct w9966_dev* cam, int device, int reg);
210
static int w9966_i2c_wreg(struct w9966_dev* cam, int device, int reg, int data);
211
 
212
static int  w9966_v4l_open(struct video_device *vdev, int mode);
213
static void w9966_v4l_close(struct video_device *vdev);
214
static int  w9966_v4l_ioctl(struct video_device *vdev,
215
                        unsigned int cmd, void *arg);
216
static long w9966_v4l_read(struct video_device *vdev,
217
                        char *buf, unsigned long count, int noblock);
218
 
219
/*
220
 *      Private function definitions
221
 */
222
 
223
// Claim parport for ourself
224
// 1 on success, else 0
225
static inline int w9966_pdev_claim(struct w9966_dev* cam)
226
{
227
        if (w9966_flag_test(cam, W9966_STATE_CLAIMED))
228
                return 1;
229
        if (parport_claim_or_block(cam->pdev) < 0)
230
                return 0;
231
        w9966_flag_set(cam, W9966_STATE_CLAIMED);
232
        return 1;
233
}
234
 
235
// Release parport for others to use
236
static inline void w9966_pdev_release(struct w9966_dev* cam)
237
{
238
        if (!w9966_flag_test(cam, W9966_STATE_CLAIMED))
239
                return;
240
        parport_release(cam->pdev);
241
        w9966_flag_clear(cam, W9966_STATE_CLAIMED);
242
}
243
 
244
// Read register from w9966 interface-chip
245
// Expects a claimed pdev
246
// -1 on error, else register data (byte)
247
static int w9966_rreg(struct w9966_dev* cam, int reg)
248
{
249
        // ECP, read, regtransfer, REG, REG, REG, REG, REG
250
        const u8 addr = 0x80 | (reg & 0x1f);
251
        u8 val;
252
 
253
        if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0 ||
254
            parport_write(cam->pport, &addr, 1) != 1 ||
255
            parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0 ||
256
            parport_read(cam->pport, &val, 1) != 1)
257
                return -1;
258
 
259
        return val;
260
}
261
 
262
// Write register to w9966 interface-chip
263
// Expects a claimed pdev
264
// 1 on success, else 0
265
static int w9966_wreg(struct w9966_dev* cam, int reg, int data)
266
{
267
        // ECP, write, regtransfer, REG, REG, REG, REG, REG
268
        const u8 addr = 0xc0 | (reg & 0x1f);
269
        const u8 val = data;
270
 
271
        if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0 ||
272
            parport_write(cam->pport, &addr, 1) != 1 ||
273
            parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0 ||
274
            parport_write(cam->pport, &val, 1) != 1)
275
                return 0;
276
 
277
        return 1;
278
}
279
 
280
// Initialize camera device. Setup all internal flags, set a
281
// default video mode, setup ccd-chip, register v4l device etc..
282
// Also used for 'probing' of hardware.
283
// 1 on success, else 0
284
static int w9966_init(struct w9966_dev* cam, struct parport* port, int vidnr)
285
{
286
        if (cam->dev_state != 0)
287
                return 0;
288
 
289
        cam->pport = port;
290
        cam->brightness = 128;
291
        cam->contrast = 64;
292
        cam->color = 64;
293
        cam->hue = 0;
294
 
295
        // Select requested transfer mode
296
        switch(parmode)
297
        {
298
        default:        // Auto-detect (priority: hw-ecp, hw-epp, sw-ecp)
299
        case 0:
300
                if (port->modes & PARPORT_MODE_ECP)
301
                        cam->ppmode = IEEE1284_MODE_ECP;
302
                else if (port->modes & PARPORT_MODE_EPP)
303
                        cam->ppmode = IEEE1284_MODE_EPP;
304
                else
305
                        cam->ppmode = IEEE1284_MODE_ECPSWE;
306
                break;
307
        case 1:         // hw- or sw-ecp
308
                if (port->modes & PARPORT_MODE_ECP)
309
                        cam->ppmode = IEEE1284_MODE_ECP;
310
                else
311
                        cam->ppmode = IEEE1284_MODE_ECPSWE;
312
                break;
313
        case 2:         // hw- or sw-epp
314
                if (port->modes & PARPORT_MODE_EPP)
315
                        cam->ppmode = IEEE1284_MODE_EPP;
316
                else
317
                        cam->ppmode = IEEE1284_MODE_EPPSWE;
318
                break;
319
        case 3:         // hw-ecp
320
                cam->ppmode = IEEE1284_MODE_ECP;
321
                break;
322
        }
323
 
324
        // Tell the parport driver that we exists
325
        cam->pdev = parport_register_device(
326
            port, W9966_DRIVERNAME, NULL, NULL, NULL, 0, NULL);
327
 
328
        if (cam->pdev == NULL) {
329
                DPRINTF("parport_register_device() failed.\n");
330
                return 0;
331
        }
332
        w9966_flag_set(cam, W9966_STATE_PDEV);
333
 
334
        // Claim parport
335
        if (!w9966_pdev_claim(cam)) {
336
                DPRINTF("w9966_pdev_claim() failed.\n");
337
                return 0;
338
        }
339
 
340
        // Perform initial w9966 setup
341
        if (!w9966_setup(cam)) {
342
                DPRINTF("w9966_setup() failed.\n");
343
                return 0;
344
        }
345
 
346
        // Detect model
347
        if (!w9966_saa7111_init(cam)) {
348
                DPRINTF("w9966_saa7111_init() failed.\n");
349
                return 0;
350
        }
351
        if (!w9966_lc99053_init(cam)) {
352
                DPRINTF("w9966_lc99053_init() failed.\n");
353
                return 0;
354
        }
355
        if (!w9966_flag_test(cam, W9966_STATE_DETECTED)) {
356
                DPRINTF("Camera model not identified.\n");
357
                return 0;
358
        }
359
 
360
        // Setup w9966 with a default capture mode (QCIF res.)
361
        if (!w9966_window(cam, 0, 0, 1023, 1023, 176, 144)) {
362
                DPRINTF("w9966_window() failed.\n");
363
                return 0;
364
        }
365
        w9966_pdev_release(cam);
366
 
367
        // Fill in the video_device struct and register us to v4l
368
        memset(&cam->vdev, 0, sizeof(struct video_device));
369
        strcpy(cam->vdev.name, W9966_DRIVERNAME);
370
        cam->vdev.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
371
        cam->vdev.hardware = VID_HARDWARE_W9966;
372
        cam->vdev.open = &w9966_v4l_open;
373
        cam->vdev.close = &w9966_v4l_close;
374
        cam->vdev.read = &w9966_v4l_read;
375
        cam->vdev.ioctl = &w9966_v4l_ioctl;
376
        cam->vdev.priv = (void*)cam;
377
        cam->vdev.owner = THIS_MODULE;
378
 
379
        if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, vidnr) == -1) {
380
                DPRINTF("video_register_device() failed (minor: %d).\n", vidnr);
381
                return 0;
382
        }
383
        w9966_flag_set(cam, W9966_STATE_VDEV);
384
 
385
        // All ok
386
        printk("w9966: Found and initialized %s on %s.\n",
387
                cam->name, cam->pport->name);
388
        return 1;
389
}
390
 
391
// Terminate everything gracefully
392
static void w9966_term(struct w9966_dev* cam)
393
{
394
        // Delete allocated buffer
395
        if (w9966_flag_test(cam, W9966_STATE_BUFFER))
396
                kfree(cam->buffer);
397
 
398
        // Unregister from v4l
399
        if (w9966_flag_test(cam, W9966_STATE_VDEV))
400
                video_unregister_device(&cam->vdev);
401
 
402
        // Terminate from IEEE1284 mode and unregister from parport
403
        if (w9966_flag_test(cam, W9966_STATE_PDEV)) {
404
                if (w9966_pdev_claim(cam))
405
                        parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
406
 
407
                w9966_pdev_release(cam);
408
                parport_unregister_device(cam->pdev);
409
        }
410
 
411
        cam->dev_state = 0x00;
412
}
413
 
414
// Do initial setup for the w9966 chip, init i2c bus, etc.
415
// this is generic for all models
416
// expects a claimed pdev
417
// 1 on success, else 0
418
static int w9966_setup(struct w9966_dev* cam)
419
{
420
        const u8 i2c = cam->i2c_state = W9966_I2C_W_DATA | W9966_I2C_W_CLOCK;
421
        const u8 regs[] = {
422
                0x40,                   // 0x13 - VEE control (raw 4:2:2)
423
                0x00, 0x00, 0x00,       // 0x14 - 0x16
424
                0x00,                   // 0x17 - ???
425
                i2c,                    // 0x18 - Serial bus
426
                0xff,                   // 0x19 - I/O port direction control
427
                0xff,                   // 0x1a - I/O port data register
428
                0x10                    // 0x1b - ???
429
        };
430
        int i;
431
 
432
        DASSERT(w9966_flag_test(cam, W9966_STATE_CLAIMED));
433
 
434
        // Reset (ECP-fifo & serial-bus)
435
        if (!w9966_wreg(cam, 0x00, 0x03) ||
436
            !w9966_wreg(cam, 0x00, 0x00))
437
                return 0;
438
 
439
        // Write regs to w9966cf chip
440
        for (i = 0x13; i < 0x1c; i++)
441
                if (!w9966_wreg(cam, i, regs[i-0x13]))
442
                        return 0;
443
 
444
        return 1;
445
}
446
 
447
// Find a good length for capture window (used both for W and H)
448
// A bit ugly but pretty functional. The capture length
449
// have to match the downscale
450
static int w9966_findlen(int near, int size, int maxlen)
451
{
452
        int bestlen = size;
453
        int besterr = abs(near - bestlen);
454
        int len;
455
 
456
        for(len = size+1; len < maxlen; len++)
457
        {
458
                int err;
459
                if ( ((64*size) %len) != 0)
460
                        continue;
461
 
462
                err = abs(near - len);
463
 
464
                // Only continue as long as we keep getting better values
465
                if (err > besterr)
466
                        break;
467
 
468
                besterr = err;
469
                bestlen = len;
470
        }
471
 
472
        return bestlen;
473
}
474
 
475
// Modify capture window (if necessary)
476
// and calculate downscaling
477
// 1 on success, else 0
478
static int w9966_calcscale(int size, int min, int max, int* beg, int* end, u8* factor)
479
{
480
        const int maxlen = max - min;
481
        const int len = *end - *beg + 1;
482
        const int newlen = w9966_findlen(len, size, maxlen);
483
        const int err = newlen - len;
484
 
485
        // Check for bad format
486
        if (newlen > maxlen || newlen < size)
487
                return 0;
488
 
489
        // Set factor (6 bit fixed)
490
        *factor = (64*size) / newlen;
491
        if (*factor == 64)
492
                *factor = 0x00; // downscale is disabled
493
        else
494
                *factor |= 0x80; // set downscale-enable bit
495
 
496
        // Modify old beginning and end
497
        *beg -= err / 2;
498
        *end += err - (err / 2);
499
 
500
        // Move window if outside borders
501
        if (*beg < min) {
502
                *end += min - *beg;
503
                *beg += min - *beg;
504
        }
505
        if (*end > max) {
506
                *beg -= *end - max;
507
                *end -= *end - max;
508
        }
509
 
510
        return 1;
511
}
512
 
513
// Setup the w9966 capture window and also set SRAM settings
514
// expects a claimed pdev and detected camera model
515
// 1 on success, else 0
516
static int w9966_window(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h)
517
{
518
        unsigned int enh_s, enh_e;
519
        u8 scale_x, scale_y;
520
        u8 regs[0x13];
521
        int i;
522
 
523
        // Modify width and height to match capture window and SRAM
524
        w = MAX(W9966_WND_MIN_W, w);
525
        h = MAX(W9966_WND_MIN_H, h);
526
        w = MIN(cam->max_x - cam->min_x, w);
527
        h = MIN(cam->max_y - cam->min_y, h);
528
        w &= ~0x1;
529
        if (w*h*2 > cam->sramsize)
530
                h = cam->sramsize / (w*2);
531
 
532
        cam->width = w;
533
        cam->height = h;
534
 
535
        enh_s = 0;
536
        enh_e = w*h*2;
537
 
538
        // Calculate downscaling
539
        if (!w9966_calcscale(w, cam->min_x, cam->max_x, &x1, &x2, &scale_x) ||
540
            !w9966_calcscale(h, cam->min_y, cam->max_y, &y1, &y2, &scale_y))
541
                return 0;
542
 
543
        DPRINTF("%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
544
                w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80);
545
 
546
        // Setup registers
547
        regs[0x00] = 0x00;                      // Set normal operation
548
        regs[0x01] = cam->cmask;                // Capture mode
549
        regs[0x02] = scale_y;                   // V-scaling
550
        regs[0x03] = scale_x;                   // H-scaling
551
 
552
        // Capture window
553
        regs[0x04] = (x1 & 0x0ff);              // X-start (8 low bits)
554
        regs[0x05] = (x1 & 0x300)>>8;           // X-start (2 high bits)
555
        regs[0x06] = (y1 & 0x0ff);              // Y-start (8 low bits)
556
        regs[0x07] = (y1 & 0x300)>>8;           // Y-start (2 high bits)
557
        regs[0x08] = (x2 & 0x0ff);              // X-end (8 low bits)
558
        regs[0x09] = (x2 & 0x300)>>8;           // X-end (2 high bits)
559
        regs[0x0a] = (y2 & 0x0ff);              // Y-end (8 low bits)
560
 
561
        regs[0x0c] = cam->sramid;               // SRAM layout
562
 
563
        // Enhancement layer
564
        regs[0x0d] = (enh_s& 0x000ff);          // Enh. start (0-7)
565
        regs[0x0e] = (enh_s& 0x0ff00)>>8;       // Enh. start (8-15)
566
        regs[0x0f] = (enh_s& 0x70000)>>16;      // Enh. start (16-17/18??)
567
        regs[0x10] = (enh_e& 0x000ff);          // Enh. end (0-7)
568
        regs[0x11] = (enh_e& 0x0ff00)>>8;       // Enh. end (8-15)
569
        regs[0x12] = (enh_e& 0x70000)>>16;      // Enh. end (16-17/18??)
570
 
571
        // Write regs to w9966cf chip
572
        for (i = 0x01; i < 0x13; i++)
573
                if (!w9966_wreg(cam, i, regs[i]))
574
                        return 0;
575
 
576
        return 1;
577
}
578
 
579
// Detect and initialize saa7111 ccd-controller chip.
580
// expects a claimed parport
581
// expected to always return 1 unless error is _fatal_
582
// 1 on success, else 0
583
static int w9966_saa7111_init(struct w9966_dev* cam)
584
{
585
        // saa7111 regs 0x00 trough 0x12
586
        const u8 regs[] = {
587
                0x00, // not written
588
                0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, 0x88, 0x10,
589
                cam->brightness,        // 0x0a
590
                cam->contrast,          // 0x0b
591
                cam->color,             // 0x0c
592
                cam->hue,               // 0x0d
593
                0x01, 0x00, 0x48, 0x0c, 0x00,
594
        };
595
        int i;
596
 
597
        if (w9966_flag_test(cam, W9966_STATE_DETECTED))
598
                return 1;
599
 
600
        // Write regs to saa7111 chip
601
        for (i = 1; i < 0x13; i++)
602
                if (!w9966_i2c_wreg(cam, W9966_SAA7111_ID, i, regs[i]))
603
                        return 1;
604
 
605
        // Read back regs
606
        for (i = 1; i < 0x13; i++)
607
                if (w9966_i2c_rreg(cam, W9966_SAA7111_ID, i) != regs[i])
608
                        return 1;
609
 
610
        // Fill in model specific data
611
        cam->name = "Lifeview Flycam Supra";
612
        cam->sramsize = 128 << 10;      // 128 kib
613
        cam->sramid = 0x02;             // see w9966.pdf
614
 
615
        cam->cmask = 0x18;              // normal polarity
616
        cam->min_x = 16;                // empirically determined
617
        cam->max_x = 705;
618
        cam->min_y = 14;
619
        cam->max_y = 253;
620
        cam->image = &w9966_saa7111_image;
621
 
622
        DPRINTF("Found and initialized a saa7111 chip.\n");
623
        w9966_flag_set(cam, W9966_STATE_DETECTED);
624
 
625
        return 1;
626
}
627
 
628
// Setup image properties (brightness, hue, etc.) for the saa7111 chip
629
// expects a claimed parport
630
// 1 on success, else 0
631
static int w9966_saa7111_image(struct w9966_dev* cam)
632
{
633
        if (!w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0a, cam->brightness) ||
634
            !w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0b, cam->contrast) ||
635
            !w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0c, cam->color) ||
636
            !w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0d, cam->hue))
637
                return 0;
638
 
639
        return 1;
640
}
641
 
642
// Detect and initialize lc99053 ccd-controller chip.
643
// expects a claimed parport
644
// this is currently a hack, no detection is done, we just assume an Eyestar2
645
// 1 on success, else 0
646
static int w9966_lc99053_init(struct w9966_dev* cam)
647
{
648
        if (w9966_flag_test(cam, W9966_STATE_DETECTED))
649
                return 1;
650
 
651
        // Fill in model specific data
652
        cam->name = "Microtek Eyestar2";
653
        cam->sramsize = 128 << 10;      // 128 kib
654
        cam->sramid = 0x02;             // w9966cf.pdf
655
 
656
        cam->cmask = 0x10;              // reverse polarity
657
        cam->min_x = 16;                // empirically determined
658
        cam->max_x = 705;
659
        cam->min_y = 14;
660
        cam->max_y = 253;
661
        cam->image = &w9966_lc99053_image;
662
 
663
        DPRINTF("Found and initialized a lc99053 chip.\n");
664
        w9966_flag_set(cam, W9966_STATE_DETECTED);
665
 
666
        return 1;
667
}
668
 
669
// Setup image properties (brightness, hue, etc.) for the lc99053 chip
670
// expects a claimed parport
671
// 1 on success, else 0
672
static int w9966_lc99053_image(struct w9966_dev* cam)
673
{
674
        return 1;
675
}
676
 
677
/*
678
 *      Ugly and primitive i2c protocol functions
679
 */
680
 
681
// Sets the data line on the i2c bus.
682
// Expects a claimed pdev.
683
static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state)
684
{
685
        if (state)
686
                cam->i2c_state |= W9966_I2C_W_DATA;
687
        else
688
                cam->i2c_state &= ~W9966_I2C_W_DATA;
689
 
690
        w9966_wreg(cam, 0x18, cam->i2c_state);
691
        udelay(W9966_I2C_UDELAY);
692
}
693
 
694
// Sets the clock line on the i2c bus.
695
// Expects a claimed pdev.
696
// 1 on success, else 0
697
static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state)
698
{
699
        if (state)
700
                cam->i2c_state |= W9966_I2C_W_CLOCK;
701
        else
702
                cam->i2c_state &= ~W9966_I2C_W_CLOCK;
703
 
704
        w9966_wreg(cam, 0x18, cam->i2c_state);
705
        udelay(W9966_I2C_UDELAY);
706
 
707
        // when we go to high, we also expect the peripheral to ack.
708
        if (state) {
709
                const int timeout = jiffies + W9966_I2C_TIMEOUT;
710
                while (!w9966_i2c_getscl(cam)) {
711
                        if (time_after(jiffies, timeout))
712
                                return 0;
713
                }
714
        }
715
        return 1;
716
}
717
 
718
// Get peripheral data line
719
// Expects a claimed pdev.
720
static inline int w9966_i2c_getsda(struct w9966_dev* cam)
721
{
722
        const u8 pins = w9966_rreg(cam, 0x18);
723
        return ((pins & W9966_I2C_R_DATA) > 0);
724
}
725
 
726
// Get peripheral clock line
727
// Expects a claimed pdev.
728
static inline int w9966_i2c_getscl(struct w9966_dev* cam)
729
{
730
        const u8 pins = w9966_rreg(cam, 0x18);
731
        return ((pins & W9966_I2C_R_CLOCK) > 0);
732
}
733
 
734
// Write a byte with ack to the i2c bus.
735
// Expects a claimed pdev.
736
// 1 on success, else 0
737
static int w9966_i2c_wbyte(struct w9966_dev* cam, int data)
738
{
739
        int i;
740
        for (i = 7; i >= 0; i--) {
741
                w9966_i2c_setsda(cam, (data >> i) & 0x01);
742
 
743
                if (!w9966_i2c_setscl(cam, 1) ||
744
                    !w9966_i2c_setscl(cam, 0))
745
                        return 0;
746
        }
747
        w9966_i2c_setsda(cam, 1);
748
 
749
        if (!w9966_i2c_setscl(cam, 1) ||
750
            !w9966_i2c_setscl(cam, 0))
751
                return 0;
752
 
753
        return 1;
754
}
755
 
756
// Read a data byte with ack from the i2c-bus
757
// Expects a claimed pdev. -1 on error
758
static int w9966_i2c_rbyte(struct w9966_dev* cam)
759
{
760
        u8 data = 0x00;
761
        int i;
762
 
763
        w9966_i2c_setsda(cam, 1);
764
 
765
        for (i = 0; i < 8; i++)
766
        {
767
                if (!w9966_i2c_setscl(cam, 1))
768
                        return -1;
769
                data = data << 1;
770
                if (w9966_i2c_getsda(cam))
771
                        data |= 0x01;
772
 
773
                w9966_i2c_setscl(cam, 0);
774
        }
775
        return data;
776
}
777
 
778
// Read a register from the i2c device.
779
// Expects claimed pdev. -1 on error
780
static int w9966_i2c_rreg(struct w9966_dev* cam, int device, int reg)
781
{
782
        int data;
783
 
784
        w9966_i2c_setsda(cam, 0);
785
        w9966_i2c_setscl(cam, 0);
786
 
787
        if (!w9966_i2c_wbyte(cam, device << 1) ||
788
            !w9966_i2c_wbyte(cam, reg))
789
                return -1;
790
 
791
        w9966_i2c_setsda(cam, 1);
792
        if (!w9966_i2c_setscl(cam, 1))
793
                return -1;
794
 
795
        w9966_i2c_setsda(cam, 0);
796
        w9966_i2c_setscl(cam, 0);
797
 
798
        if (!w9966_i2c_wbyte(cam, (device << 1) | 1) ||
799
            (data = w9966_i2c_rbyte(cam)) == -1)
800
                return -1;
801
 
802
        w9966_i2c_setsda(cam, 0);
803
 
804
        if (!w9966_i2c_setscl(cam, 1))
805
                return -1;
806
 
807
        w9966_i2c_setsda(cam, 1);
808
 
809
        return data;
810
}
811
 
812
// Write a register to the i2c device.
813
// Expects claimed pdev.
814
// 1 on success, else 0
815
static int w9966_i2c_wreg(struct w9966_dev* cam, int device, int reg, int data)
816
{
817
        w9966_i2c_setsda(cam, 0);
818
        w9966_i2c_setscl(cam, 0);
819
 
820
        if (!w9966_i2c_wbyte(cam, device << 1) ||
821
            !w9966_i2c_wbyte(cam, reg) ||
822
            !w9966_i2c_wbyte(cam, data))
823
                return 0;
824
 
825
        w9966_i2c_setsda(cam, 0);
826
        if (!w9966_i2c_setscl(cam, 1))
827
                return 0;
828
 
829
        w9966_i2c_setsda(cam, 1);
830
 
831
        return 1;
832
}
833
 
834
/*
835
 *      Video4linux interface
836
 */
837
 
838
static int w9966_v4l_open(struct video_device *vdev, int flags)
839
{
840
        struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
841
 
842
        // Claim parport
843
        if (!w9966_pdev_claim(cam)) {
844
                DPRINTF("Unable to claim parport");
845
                return -EFAULT;
846
        }
847
 
848
        // Allocate read buffer
849
        cam->buffer = (u8*)kmalloc(W9966_RBUFFER, GFP_KERNEL);
850
        if (cam->buffer == NULL) {
851
                w9966_pdev_release(cam);
852
                return -ENOMEM;
853
        }
854
        w9966_flag_set(cam, W9966_STATE_BUFFER);
855
 
856
        return 0;
857
}
858
 
859
static void w9966_v4l_close(struct video_device *vdev)
860
{
861
        struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
862
 
863
        // Free read buffer
864
        if (w9966_flag_test(cam, W9966_STATE_BUFFER)) {
865
                kfree(cam->buffer);
866
                w9966_flag_clear(cam, W9966_STATE_BUFFER);
867
        }
868
 
869
        // release parport
870
        w9966_pdev_release(cam);
871
}
872
 
873
// expects a claimed parport
874
static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
875
{
876
        struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
877
 
878
        switch(cmd)
879
        {
880
        case VIDIOCGCAP:
881
        {
882
                struct video_capability vcap = {
883
                        W9966_DRIVERNAME,       // name
884
                        VID_TYPE_CAPTURE | VID_TYPE_SCALES,     // type
885
                        1, 0,                    // vid, aud channels
886
                        cam->max_x - cam->min_x,
887
                        cam->max_y - cam->min_y,
888
                        W9966_WND_MIN_W,
889
                        W9966_WND_MIN_H
890
                };
891
 
892
                if(copy_to_user(arg, &vcap, sizeof(vcap)) != 0)
893
                        return -EFAULT;
894
 
895
                return 0;
896
        }
897
        case VIDIOCGCHAN:
898
        {
899
                struct video_channel vch;
900
                if(copy_from_user(&vch, arg, sizeof(vch)) != 0)
901
                        return -EFAULT;
902
 
903
                if(vch.channel != 0)     // We only support one channel (#0)
904
                        return -EINVAL;
905
 
906
                strcpy(vch.name, "CCD-input");
907
                vch.flags = 0;           // We have no tuner or audio
908
                vch.tuners = 0;
909
                vch.type = VIDEO_TYPE_CAMERA;
910
                vch.norm = 0;            // ???
911
 
912
                if(copy_to_user(arg, &vch, sizeof(vch)) != 0)
913
                        return -EFAULT;
914
 
915
                return 0;
916
        }
917
        case VIDIOCSCHAN:
918
        {
919
                struct video_channel vch;
920
                if(copy_from_user(&vch, arg, sizeof(vch) ) != 0)
921
                        return -EFAULT;
922
 
923
                if(vch.channel != 0)
924
                        return -EINVAL;
925
 
926
                return 0;
927
        }
928
        case VIDIOCGTUNER:
929
        {
930
                struct video_tuner vtune;
931
                if(copy_from_user(&vtune, arg, sizeof(vtune)) != 0)
932
                        return -EFAULT;
933
 
934
                if(vtune.tuner != 0)
935
                        return -EINVAL;
936
 
937
                strcpy(vtune.name, "no tuner");
938
                vtune.rangelow = 0;
939
                vtune.rangehigh = 0;
940
                vtune.flags = VIDEO_TUNER_NORM;
941
                vtune.mode = VIDEO_MODE_AUTO;
942
                vtune.signal = 0xffff;
943
 
944
                if(copy_to_user(arg, &vtune, sizeof(vtune)) != 0)
945
                        return -EFAULT;
946
 
947
                return 0;
948
        }
949
        case VIDIOCSTUNER:
950
        {
951
                struct video_tuner vtune;
952
                if (copy_from_user(&vtune, arg, sizeof(vtune)) != 0)
953
                        return -EFAULT;
954
 
955
                if (vtune.tuner != 0)
956
                        return -EINVAL;
957
 
958
                if (vtune.mode != VIDEO_MODE_AUTO)
959
                        return -EINVAL;
960
 
961
                return 0;
962
        }
963
        case VIDIOCGPICT:
964
        {
965
                struct video_picture vpic = {
966
                        cam->brightness << 8,   // brightness
967
                        (cam->hue + 128) << 8,  // hue
968
                        cam->color << 9,        // color
969
                        cam->contrast << 9,     // contrast
970
                        0x8000,                 // whiteness
971
                        16, VIDEO_PALETTE_YUV422// bpp, palette format
972
                };
973
 
974
                if(copy_to_user(arg, &vpic, sizeof(vpic)) != 0)
975
                        return -EFAULT;
976
 
977
                return 0;
978
        }
979
        case VIDIOCSPICT:
980
        {
981
                struct video_picture vpic;
982
                if(copy_from_user(&vpic, arg, sizeof(vpic)) != 0)
983
                        return -EFAULT;
984
 
985
                if (vpic.depth != 16 || vpic.palette != VIDEO_PALETTE_YUV422)
986
                        return -EINVAL;
987
 
988
                cam->brightness = vpic.brightness >> 8;
989
                cam->hue = (vpic.hue >> 8) - 128;
990
                cam->color = vpic.colour >> 9;
991
                cam->contrast = vpic.contrast >> 9;
992
 
993
                if (!cam->image(cam))
994
                        return -EFAULT;
995
 
996
                return 0;
997
        }
998
        case VIDIOCSWIN:
999
        {
1000
                struct video_window vwin;
1001
 
1002
                if (copy_from_user(&vwin, arg, sizeof(vwin)) != 0)
1003
                        return -EFAULT;
1004
                if (
1005
                  vwin.flags != 0 ||
1006
                  vwin.clipcount != 0)
1007
                        return -EINVAL;
1008
 
1009
                if (vwin.width  > cam->max_x - cam->min_x ||
1010
                    vwin.height > cam->max_y - cam->min_y ||
1011
                    vwin.width  < W9966_WND_MIN_W ||
1012
                    vwin.height < W9966_WND_MIN_H)
1013
                        return -EINVAL;
1014
 
1015
                // Update camera regs
1016
                if (!w9966_window(cam, 0, 0, 1023, 1023, vwin.width, vwin.height))
1017
                        return -EFAULT;
1018
 
1019
                return 0;
1020
        }
1021
        case VIDIOCGWIN:
1022
        {
1023
                struct video_window vwin;
1024
                memset(&vwin, 0, sizeof(vwin));
1025
 
1026
                vwin.width = cam->width;
1027
                vwin.height = cam->height;
1028
 
1029
                if(copy_to_user(arg, &vwin, sizeof(vwin)) != 0)
1030
                        return -EFAULT;
1031
 
1032
                return 0;
1033
        }
1034
        // Unimplemented
1035
        case VIDIOCCAPTURE:
1036
        case VIDIOCGFBUF:
1037
        case VIDIOCSFBUF:
1038
        case VIDIOCKEY:
1039
        case VIDIOCGFREQ:
1040
        case VIDIOCSFREQ:
1041
        case VIDIOCGAUDIO:
1042
        case VIDIOCSAUDIO:
1043
                return -EINVAL;
1044
        default:
1045
                return -ENOIOCTLCMD;
1046
        }
1047
        return 0;
1048
}
1049
 
1050
// Capture data
1051
// expects a claimed parport and allocated read buffer
1052
static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count,  int noblock)
1053
{
1054
        struct w9966_dev *cam = (struct w9966_dev *)vdev->priv;
1055
        const u8 addr = 0xa0;   // ECP, read, CCD-transfer, 00000
1056
        u8* dest = (u8*)buf;
1057
        unsigned long dleft = count;
1058
 
1059
        // Why would anyone want more than this??
1060
        if (count > cam->width * cam->height * 2)
1061
                count = cam->width * cam->height * 2;
1062
 
1063
        w9966_wreg(cam, 0x00, 0x02);    // Reset ECP-FIFO buffer
1064
        w9966_wreg(cam, 0x00, 0x00);    // Return to normal operation
1065
        w9966_wreg(cam, 0x01, cam->cmask | 0x80);       // Enable capture
1066
 
1067
        // write special capture-addr and negotiate into data transfer
1068
        if (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0 ||
1069
            parport_write(cam->pport, &addr, 1) != 1 ||
1070
            parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0) {
1071
                DPRINTF("Unable to write capture-addr.\n");
1072
                return -EFAULT;
1073
        }
1074
 
1075
        while(dleft > 0)
1076
        {
1077
                const size_t tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
1078
 
1079
                if (parport_read(cam->pport, cam->buffer, tsize) < tsize)
1080
                        return -EFAULT;
1081
 
1082
                if (copy_to_user(dest, cam->buffer, tsize) != 0)
1083
                        return -EFAULT;
1084
 
1085
                dest += tsize;
1086
                dleft -= tsize;
1087
        }
1088
 
1089
        w9966_wreg(cam, 0x01, cam->cmask);      // Disable capture
1090
 
1091
        return count;
1092
}
1093
 
1094
// Called once for every parport on init
1095
static void w9966_attach(struct parport *port)
1096
{
1097
        int i;
1098
 
1099
        for (i = 0; i < W9966_MAXCAMS; i++) {
1100
                if (strcmp(pardev[i], "none") == 0 ||    // Skip if 'none' or if
1101
                    w9966_cams[i].dev_state != 0)        // cam already assigned
1102
                        continue;
1103
 
1104
                if (strcmp(pardev[i], "auto") == 0 ||
1105
                    strcmp(pardev[i], port->name) == 0) {
1106
                        if (!w9966_init(&w9966_cams[i], port, video_nr[i]))
1107
                                w9966_term(&w9966_cams[i]);
1108
                        break;  // return
1109
                }
1110
        }
1111
}
1112
 
1113
// Called once for every parport on termination
1114
static void w9966_detach(struct parport *port)
1115
{
1116
        int i;
1117
        for (i = 0; i < W9966_MAXCAMS; i++)
1118
        if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
1119
                w9966_term(&w9966_cams[i]);
1120
}
1121
 
1122
 
1123
static struct parport_driver w9966_ppd = {
1124
        W9966_DRIVERNAME,
1125
        w9966_attach,
1126
        w9966_detach,
1127
        NULL
1128
};
1129
 
1130
// Module entry point
1131
static int __init w9966_mod_init(void)
1132
{
1133
        int i, err;
1134
 
1135
        w9966_cams = kmalloc(
1136
                sizeof(struct w9966_dev) * W9966_MAXCAMS, GFP_KERNEL);
1137
 
1138
        if (!w9966_cams)
1139
                return -ENOMEM;
1140
 
1141
        for (i = 0; i < W9966_MAXCAMS; i++)
1142
                w9966_cams[i].dev_state = 0;
1143
 
1144
        // Register parport driver
1145
        if ((err = parport_register_driver(&w9966_ppd)) != 0) {
1146
                kfree(w9966_cams);
1147
                w9966_cams = 0;
1148
                return err;
1149
        }
1150
 
1151
        return 0;
1152
}
1153
 
1154
// Module cleanup
1155
static void __exit w9966_mod_term(void)
1156
{
1157
        if (w9966_cams)
1158
                kfree(w9966_cams);
1159
 
1160
        parport_unregister_driver(&w9966_ppd);
1161
}
1162
 
1163
module_init(w9966_mod_init);
1164
module_exit(w9966_mod_term);

powered by: WebSVN 2.1.0

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