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

Subversion Repositories test_project

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
        Winbond w9966cf Webcam parport driver.
3
 
4
        Version 0.32
5
 
6
        Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se>
7
 
8
        This program is free software; you can redistribute it and/or modify
9
        it under the terms of the GNU General Public License as published by
10
        the Free Software Foundation; either version 2 of the License, or
11
        (at your option) any later version.
12
 
13
        This program is distributed in the hope that it will be useful,
14
        but WITHOUT ANY WARRANTY; without even the implied warranty of
15
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
        GNU General Public License for more details.
17
 
18
        You should have received a copy of the GNU General Public License
19
        along with this program; if not, write to the Free Software
20
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
*/
22
/*
23
        Supported devices:
24
        *Lifeview FlyCam Supra (using the Philips saa7111a chip)
25
 
26
        Does any other model using the w9966 interface chip exist ?
27
 
28
        Todo:
29
 
30
        *Add a working EPP mode, since DMA ECP read isn't implemented
31
        in the parport drivers. (That's why it's so sloow)
32
 
33
        *Add support for other ccd-control chips than the saa7111
34
        please send me feedback on what kind of chips you have.
35
 
36
        *Add proper probing. I don't know what's wrong with the IEEE1284
37
        parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID)
38
        and nibble read seems to be broken for some peripherals.
39
 
40
        *Add probing for onboard SRAM, port directions etc. (if possible)
41
 
42
        *Add support for the hardware compressed modes (maybe using v4l2)
43
 
44
        *Fix better support for the capture window (no skewed images, v4l
45
        interface to capt. window)
46
 
47
        *Probably some bugs that I don't know of
48
 
49
        Please support me by sending feedback!
50
 
51
        Changes:
52
 
53
        Alan Cox:       Removed RGB mode for kernel merge, added THIS_MODULE
54
                        and owner support for newer module locks
55
*/
56
 
57
#include <linux/module.h>
58
#include <linux/init.h>
59
#include <linux/delay.h>
60
#include <linux/videodev.h>
61
#include <media/v4l2-common.h>
62
#include <linux/parport.h>
63
 
64
//#define DEBUG                         // Undef me for production
65
 
66
#ifdef DEBUG
67
#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __FUNCTION__ , ##a)
68
#else
69
#define DPRINTF(x...)
70
#endif
71
 
72
/*
73
 *      Defines, simple typedefs etc.
74
 */
75
 
76
#define W9966_DRIVERNAME        "W9966CF Webcam"
77
#define W9966_MAXCAMS           4       // Maximum number of cameras
78
#define W9966_RBUFFER           2048    // Read buffer (must be an even number)
79
#define W9966_SRAMSIZE          131072  // 128kb
80
#define W9966_SRAMID            0x02    // check w9966cf.pdf
81
 
82
// Empirically determined window limits
83
#define W9966_WND_MIN_X         16
84
#define W9966_WND_MIN_Y         14
85
#define W9966_WND_MAX_X         705
86
#define W9966_WND_MAX_Y         253
87
#define W9966_WND_MAX_W         (W9966_WND_MAX_X - W9966_WND_MIN_X)
88
#define W9966_WND_MAX_H         (W9966_WND_MAX_Y - W9966_WND_MIN_Y)
89
 
90
// Keep track of our current state
91
#define W9966_STATE_PDEV        0x01
92
#define W9966_STATE_CLAIMED     0x02
93
#define W9966_STATE_VDEV        0x04
94
 
95
#define W9966_I2C_W_ID          0x48
96
#define W9966_I2C_R_ID          0x49
97
#define W9966_I2C_R_DATA        0x08
98
#define W9966_I2C_R_CLOCK       0x04
99
#define W9966_I2C_W_DATA        0x02
100
#define W9966_I2C_W_CLOCK       0x01
101
 
102
struct w9966_dev {
103
        unsigned char dev_state;
104
        unsigned char i2c_state;
105
        unsigned short ppmode;
106
        struct parport* pport;
107
        struct pardevice* pdev;
108
        struct video_device vdev;
109
        unsigned short width;
110
        unsigned short height;
111
        unsigned char brightness;
112
        signed char contrast;
113
        signed char color;
114
        signed char hue;
115
};
116
 
117
/*
118
 *      Module specific properties
119
 */
120
 
121
MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
122
MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
123
MODULE_LICENSE("GPL");
124
 
125
 
126
#ifdef MODULE
127
static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""};
128
#else
129
static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
130
#endif
131
module_param_array(pardev, charp, NULL, 0);
132
MODULE_PARM_DESC(pardev, "pardev: where to search for\n\
133
\teach camera. 'aggressive' means brute-force search.\n\
134
\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n\
135
\tcam 1 to parport3 and search every parport for cam 2 etc...");
136
 
137
static int parmode = 0;
138
module_param(parmode, int, 0);
139
MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
140
 
141
static int video_nr = -1;
142
module_param(video_nr, int, 0);
143
 
144
/*
145
 *      Private data
146
 */
147
 
148
static struct w9966_dev w9966_cams[W9966_MAXCAMS];
149
 
150
/*
151
 *      Private function declares
152
 */
153
 
154
static inline void w9966_setState(struct w9966_dev* cam, int mask, int val);
155
static inline int  w9966_getState(struct w9966_dev* cam, int mask, int val);
156
static inline void w9966_pdev_claim(struct w9966_dev *vdev);
157
static inline void w9966_pdev_release(struct w9966_dev *vdev);
158
 
159
static int w9966_rReg(struct w9966_dev* cam, int reg);
160
static int w9966_wReg(struct w9966_dev* cam, int reg, int data);
161
#if 0
162
static int w9966_rReg_i2c(struct w9966_dev* cam, int reg);
163
#endif
164
static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data);
165
static int w9966_findlen(int near, int size, int maxlen);
166
static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor);
167
static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h);
168
 
169
static int  w9966_init(struct w9966_dev* cam, struct parport* port);
170
static void w9966_term(struct w9966_dev* cam);
171
 
172
static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state);
173
static inline int  w9966_i2c_setscl(struct w9966_dev* cam, int state);
174
static inline int  w9966_i2c_getsda(struct w9966_dev* cam);
175
static inline int  w9966_i2c_getscl(struct w9966_dev* cam);
176
static int w9966_i2c_wbyte(struct w9966_dev* cam, int data);
177
#if 0
178
static int w9966_i2c_rbyte(struct w9966_dev* cam);
179
#endif
180
 
181
static int w9966_v4l_ioctl(struct inode *inode, struct file *file,
182
                           unsigned int cmd, unsigned long arg);
183
static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
184
                              size_t count, loff_t *ppos);
185
 
186
static const struct file_operations w9966_fops = {
187
        .owner          = THIS_MODULE,
188
        .open           = video_exclusive_open,
189
        .release        = video_exclusive_release,
190
        .ioctl          = w9966_v4l_ioctl,
191
        .compat_ioctl   = v4l_compat_ioctl32,
192
        .read           = w9966_v4l_read,
193
        .llseek         = no_llseek,
194
};
195
static struct video_device w9966_template = {
196
        .owner          = THIS_MODULE,
197
        .name           = W9966_DRIVERNAME,
198
        .type           = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
199
        .fops           = &w9966_fops,
200
};
201
 
202
/*
203
 *      Private function defines
204
 */
205
 
206
 
207
// Set camera phase flags, so we know what to uninit when terminating
208
static inline void w9966_setState(struct w9966_dev* cam, int mask, int val)
209
{
210
        cam->dev_state = (cam->dev_state & ~mask) ^ val;
211
}
212
 
213
// Get camera phase flags
214
static inline int w9966_getState(struct w9966_dev* cam, int mask, int val)
215
{
216
        return ((cam->dev_state & mask) == val);
217
}
218
 
219
// Claim parport for ourself
220
static inline void w9966_pdev_claim(struct w9966_dev* cam)
221
{
222
        if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
223
                return;
224
        parport_claim_or_block(cam->pdev);
225
        w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
226
}
227
 
228
// Release parport for others to use
229
static inline void w9966_pdev_release(struct w9966_dev* cam)
230
{
231
        if (w9966_getState(cam, W9966_STATE_CLAIMED, 0))
232
                return;
233
        parport_release(cam->pdev);
234
        w9966_setState(cam, W9966_STATE_CLAIMED, 0);
235
}
236
 
237
// Read register from W9966 interface-chip
238
// Expects a claimed pdev
239
// -1 on error, else register data (byte)
240
static int w9966_rReg(struct w9966_dev* cam, int reg)
241
{
242
        // ECP, read, regtransfer, REG, REG, REG, REG, REG
243
        const unsigned char addr = 0x80 | (reg & 0x1f);
244
        unsigned char val;
245
 
246
        if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
247
                return -1;
248
        if (parport_write(cam->pport, &addr, 1) != 1)
249
                return -1;
250
        if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
251
                return -1;
252
        if (parport_read(cam->pport, &val, 1) != 1)
253
                return -1;
254
 
255
        return val;
256
}
257
 
258
// Write register to W9966 interface-chip
259
// Expects a claimed pdev
260
// -1 on error
261
static int w9966_wReg(struct w9966_dev* cam, int reg, int data)
262
{
263
        // ECP, write, regtransfer, REG, REG, REG, REG, REG
264
        const unsigned char addr = 0xc0 | (reg & 0x1f);
265
        const unsigned char val = data;
266
 
267
        if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
268
                return -1;
269
        if (parport_write(cam->pport, &addr, 1) != 1)
270
                return -1;
271
        if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
272
                return -1;
273
        if (parport_write(cam->pport, &val, 1) != 1)
274
                return -1;
275
 
276
        return 0;
277
}
278
 
279
// Initialize camera device. Setup all internal flags, set a
280
// default video mode, setup ccd-chip, register v4l device etc..
281
// Also used for 'probing' of hardware.
282
// -1 on error
283
static int w9966_init(struct w9966_dev* cam, struct parport* port)
284
{
285
        if (cam->dev_state != 0)
286
                return -1;
287
 
288
        cam->pport = port;
289
        cam->brightness = 128;
290
        cam->contrast = 64;
291
        cam->color = 64;
292
        cam->hue = 0;
293
 
294
// Select requested transfer mode
295
        switch(parmode)
296
        {
297
        default:        // Auto-detect (priority: hw-ecp, hw-epp, sw-ecp)
298
        case 0:
299
                if (port->modes & PARPORT_MODE_ECP)
300
                        cam->ppmode = IEEE1284_MODE_ECP;
301
                else if (port->modes & PARPORT_MODE_EPP)
302
                        cam->ppmode = IEEE1284_MODE_EPP;
303
                else
304
                        cam->ppmode = IEEE1284_MODE_ECP;
305
                break;
306
        case 1:         // hw- or sw-ecp
307
                cam->ppmode = IEEE1284_MODE_ECP;
308
                break;
309
        case 2:         // hw- or sw-epp
310
                cam->ppmode = IEEE1284_MODE_EPP;
311
        break;
312
        }
313
 
314
// Tell the parport driver that we exists
315
        cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
316
        if (cam->pdev == NULL) {
317
                DPRINTF("parport_register_device() failed\n");
318
                return -1;
319
        }
320
        w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
321
 
322
        w9966_pdev_claim(cam);
323
 
324
// Setup a default capture mode
325
        if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
326
                DPRINTF("w9966_setup() failed.\n");
327
                return -1;
328
        }
329
 
330
        w9966_pdev_release(cam);
331
 
332
// Fill in the video_device struct and register us to v4l
333
        memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
334
        cam->vdev.priv = cam;
335
 
336
        if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1)
337
                return -1;
338
 
339
        w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
340
 
341
        // All ok
342
        printk(
343
                "w9966cf: Found and initialized a webcam on %s.\n",
344
                cam->pport->name
345
        );
346
        return 0;
347
}
348
 
349
 
350
// Terminate everything gracefully
351
static void w9966_term(struct w9966_dev* cam)
352
{
353
// Unregister from v4l
354
        if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
355
                video_unregister_device(&cam->vdev);
356
                w9966_setState(cam, W9966_STATE_VDEV, 0);
357
        }
358
 
359
// Terminate from IEEE1284 mode and release pdev block
360
        if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
361
                w9966_pdev_claim(cam);
362
                parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
363
                w9966_pdev_release(cam);
364
        }
365
 
366
// Unregister from parport
367
        if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
368
                parport_unregister_device(cam->pdev);
369
                w9966_setState(cam, W9966_STATE_PDEV, 0);
370
        }
371
}
372
 
373
 
374
// Find a good length for capture window (used both for W and H)
375
// A bit ugly but pretty functional. The capture length
376
// have to match the downscale
377
static int w9966_findlen(int near, int size, int maxlen)
378
{
379
        int bestlen = size;
380
        int besterr = abs(near - bestlen);
381
        int len;
382
 
383
        for(len = size+1;len < maxlen;len++)
384
        {
385
                int err;
386
                if ( ((64*size) %len) != 0)
387
                        continue;
388
 
389
                err = abs(near - len);
390
 
391
                // Only continue as long as we keep getting better values
392
                if (err > besterr)
393
                        break;
394
 
395
                besterr = err;
396
                bestlen = len;
397
        }
398
 
399
        return bestlen;
400
}
401
 
402
// Modify capture window (if necessary)
403
// and calculate downscaling
404
// Return -1 on error
405
static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor)
406
{
407
        int maxlen = max - min;
408
        int len = *end - *beg + 1;
409
        int newlen = w9966_findlen(len, size, maxlen);
410
        int err = newlen - len;
411
 
412
        // Check for bad format
413
        if (newlen > maxlen || newlen < size)
414
                return -1;
415
 
416
        // Set factor (6 bit fixed)
417
        *factor = (64*size) / newlen;
418
        if (*factor == 64)
419
                *factor = 0x00; // downscale is disabled
420
        else
421
                *factor |= 0x80; // set downscale-enable bit
422
 
423
        // Modify old beginning and end
424
        *beg -= err / 2;
425
        *end += err - (err / 2);
426
 
427
        // Move window if outside borders
428
        if (*beg < min) {
429
                *end += min - *beg;
430
                *beg += min - *beg;
431
        }
432
        if (*end > max) {
433
                *beg -= *end - max;
434
                *end -= *end - max;
435
        }
436
 
437
        return 0;
438
}
439
 
440
// Setup the cameras capture window etc.
441
// Expects a claimed pdev
442
// return -1 on error
443
static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h)
444
{
445
        unsigned int i;
446
        unsigned int enh_s, enh_e;
447
        unsigned char scale_x, scale_y;
448
        unsigned char regs[0x1c];
449
        unsigned char saa7111_regs[] = {
450
                0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
451
                0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
452
                0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
453
                0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
454
        };
455
 
456
 
457
        if (w*h*2 > W9966_SRAMSIZE)
458
        {
459
                DPRINTF("capture window exceeds SRAM size!.\n");
460
                w = 200; h = 160;       // Pick default values
461
        }
462
 
463
        w &= ~0x1;
464
        if (w < 2) w = 2;
465
        if (h < 1) h = 1;
466
        if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W;
467
        if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H;
468
 
469
        cam->width = w;
470
        cam->height = h;
471
 
472
        enh_s = 0;
473
        enh_e = w*h*2;
474
 
475
// Modify capture window if necessary and calculate downscaling
476
        if (
477
                w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
478
                w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0
479
        ) return -1;
480
 
481
        DPRINTF(
482
                "%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
483
                w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80
484
        );
485
 
486
// Setup registers
487
        regs[0x00] = 0x00;                      // Set normal operation
488
        regs[0x01] = 0x18;                      // Capture mode
489
        regs[0x02] = scale_y;                   // V-scaling
490
        regs[0x03] = scale_x;                   // H-scaling
491
 
492
        // Capture window
493
        regs[0x04] = (x1 & 0x0ff);              // X-start (8 low bits)
494
        regs[0x05] = (x1 & 0x300)>>8;           // X-start (2 high bits)
495
        regs[0x06] = (y1 & 0x0ff);              // Y-start (8 low bits)
496
        regs[0x07] = (y1 & 0x300)>>8;           // Y-start (2 high bits)
497
        regs[0x08] = (x2 & 0x0ff);              // X-end (8 low bits)
498
        regs[0x09] = (x2 & 0x300)>>8;           // X-end (2 high bits)
499
        regs[0x0a] = (y2 & 0x0ff);              // Y-end (8 low bits)
500
 
501
        regs[0x0c] = W9966_SRAMID;              // SRAM-banks (1x 128kb)
502
 
503
        // Enhancement layer
504
        regs[0x0d] = (enh_s& 0x000ff);          // Enh. start (0-7)
505
        regs[0x0e] = (enh_s& 0x0ff00)>>8;       // Enh. start (8-15)
506
        regs[0x0f] = (enh_s& 0x70000)>>16;      // Enh. start (16-17/18??)
507
        regs[0x10] = (enh_e& 0x000ff);          // Enh. end (0-7)
508
        regs[0x11] = (enh_e& 0x0ff00)>>8;       // Enh. end (8-15)
509
        regs[0x12] = (enh_e& 0x70000)>>16;      // Enh. end (16-17/18??)
510
 
511
        // Misc
512
        regs[0x13] = 0x40;                      // VEE control (raw 4:2:2)
513
        regs[0x17] = 0x00;                      // ???
514
        regs[0x18] = cam->i2c_state = 0x00;     // Serial bus
515
        regs[0x19] = 0xff;                      // I/O port direction control
516
        regs[0x1a] = 0xff;                      // I/O port data register
517
        regs[0x1b] = 0x10;                      // ???
518
 
519
        // SAA7111 chip settings
520
        saa7111_regs[0x0a] = cam->brightness;
521
        saa7111_regs[0x0b] = cam->contrast;
522
        saa7111_regs[0x0c] = cam->color;
523
        saa7111_regs[0x0d] = cam->hue;
524
 
525
// Reset (ECP-fifo & serial-bus)
526
        if (w9966_wReg(cam, 0x00, 0x03) == -1)
527
                return -1;
528
 
529
// Write regs to w9966cf chip
530
        for (i = 0; i < 0x1c; i++)
531
                if (w9966_wReg(cam, i, regs[i]) == -1)
532
                        return -1;
533
 
534
// Write regs to saa7111 chip
535
        for (i = 0; i < 0x20; i++)
536
                if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1)
537
                        return -1;
538
 
539
        return 0;
540
}
541
 
542
/*
543
 *      Ugly and primitive i2c protocol functions
544
 */
545
 
546
// Sets the data line on the i2c bus.
547
// Expects a claimed pdev.
548
static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state)
549
{
550
        if (state)
551
                cam->i2c_state |= W9966_I2C_W_DATA;
552
        else
553
                cam->i2c_state &= ~W9966_I2C_W_DATA;
554
 
555
        w9966_wReg(cam, 0x18, cam->i2c_state);
556
        udelay(5);
557
}
558
 
559
// Get peripheral clock line
560
// Expects a claimed pdev.
561
static inline int w9966_i2c_getscl(struct w9966_dev* cam)
562
{
563
        const unsigned char state = w9966_rReg(cam, 0x18);
564
        return ((state & W9966_I2C_R_CLOCK) > 0);
565
}
566
 
567
// Sets the clock line on the i2c bus.
568
// Expects a claimed pdev. -1 on error
569
static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state)
570
{
571
        unsigned long timeout;
572
 
573
        if (state)
574
                cam->i2c_state |= W9966_I2C_W_CLOCK;
575
        else
576
                cam->i2c_state &= ~W9966_I2C_W_CLOCK;
577
 
578
        w9966_wReg(cam, 0x18, cam->i2c_state);
579
        udelay(5);
580
 
581
        // we go to high, we also expect the peripheral to ack.
582
        if (state) {
583
                timeout = jiffies + 100;
584
                while (!w9966_i2c_getscl(cam)) {
585
                        if (time_after(jiffies, timeout))
586
                                return -1;
587
                }
588
        }
589
        return 0;
590
}
591
 
592
// Get peripheral data line
593
// Expects a claimed pdev.
594
static inline int w9966_i2c_getsda(struct w9966_dev* cam)
595
{
596
        const unsigned char state = w9966_rReg(cam, 0x18);
597
        return ((state & W9966_I2C_R_DATA) > 0);
598
}
599
 
600
// Write a byte with ack to the i2c bus.
601
// Expects a claimed pdev. -1 on error
602
static int w9966_i2c_wbyte(struct w9966_dev* cam, int data)
603
{
604
        int i;
605
        for (i = 7; i >= 0; i--)
606
        {
607
                w9966_i2c_setsda(cam, (data >> i) & 0x01);
608
 
609
                if (w9966_i2c_setscl(cam, 1) == -1)
610
                        return -1;
611
                w9966_i2c_setscl(cam, 0);
612
        }
613
 
614
        w9966_i2c_setsda(cam, 1);
615
 
616
        if (w9966_i2c_setscl(cam, 1) == -1)
617
                return -1;
618
        w9966_i2c_setscl(cam, 0);
619
 
620
        return 0;
621
}
622
 
623
// Read a data byte with ack from the i2c-bus
624
// Expects a claimed pdev. -1 on error
625
#if 0
626
static int w9966_i2c_rbyte(struct w9966_dev* cam)
627
{
628
        unsigned char data = 0x00;
629
        int i;
630
 
631
        w9966_i2c_setsda(cam, 1);
632
 
633
        for (i = 0; i < 8; i++)
634
        {
635
                if (w9966_i2c_setscl(cam, 1) == -1)
636
                        return -1;
637
                data = data << 1;
638
                if (w9966_i2c_getsda(cam))
639
                        data |= 0x01;
640
 
641
                w9966_i2c_setscl(cam, 0);
642
        }
643
        return data;
644
}
645
#endif
646
 
647
// Read a register from the i2c device.
648
// Expects claimed pdev. -1 on error
649
#if 0
650
static int w9966_rReg_i2c(struct w9966_dev* cam, int reg)
651
{
652
        int data;
653
 
654
        w9966_i2c_setsda(cam, 0);
655
        w9966_i2c_setscl(cam, 0);
656
 
657
        if (
658
                w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
659
                w9966_i2c_wbyte(cam, reg) == -1
660
        )
661
                return -1;
662
 
663
        w9966_i2c_setsda(cam, 1);
664
        if (w9966_i2c_setscl(cam, 1) == -1)
665
                return -1;
666
        w9966_i2c_setsda(cam, 0);
667
        w9966_i2c_setscl(cam, 0);
668
 
669
        if (
670
                w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1 ||
671
                (data = w9966_i2c_rbyte(cam)) == -1
672
        )
673
                return -1;
674
 
675
        w9966_i2c_setsda(cam, 0);
676
 
677
        if (w9966_i2c_setscl(cam, 1) == -1)
678
                return -1;
679
        w9966_i2c_setsda(cam, 1);
680
 
681
        return data;
682
}
683
#endif
684
 
685
// Write a register to the i2c device.
686
// Expects claimed pdev. -1 on error
687
static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
688
{
689
        w9966_i2c_setsda(cam, 0);
690
        w9966_i2c_setscl(cam, 0);
691
 
692
        if (
693
                w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
694
                w9966_i2c_wbyte(cam, reg) == -1 ||
695
                w9966_i2c_wbyte(cam, data) == -1
696
        )
697
                return -1;
698
 
699
        w9966_i2c_setsda(cam, 0);
700
        if (w9966_i2c_setscl(cam, 1) == -1)
701
                return -1;
702
 
703
        w9966_i2c_setsda(cam, 1);
704
 
705
        return 0;
706
}
707
 
708
/*
709
 *      Video4linux interfacing
710
 */
711
 
712
static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
713
                              unsigned int cmd, void *arg)
714
{
715
        struct video_device *vdev = video_devdata(file);
716
        struct w9966_dev *cam = vdev->priv;
717
 
718
        switch(cmd)
719
        {
720
        case VIDIOCGCAP:
721
        {
722
                static struct video_capability vcap = {
723
                        .name      = W9966_DRIVERNAME,
724
                        .type      = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
725
                        .channels  = 1,
726
                        .maxwidth  = W9966_WND_MAX_W,
727
                        .maxheight = W9966_WND_MAX_H,
728
                        .minwidth  = 2,
729
                        .minheight = 1,
730
                };
731
                struct video_capability *cap = arg;
732
                *cap = vcap;
733
                return 0;
734
        }
735
        case VIDIOCGCHAN:
736
        {
737
                struct video_channel *vch = arg;
738
                if(vch->channel != 0)    // We only support one channel (#0)
739
                        return -EINVAL;
740
                memset(vch,0,sizeof(*vch));
741
                strcpy(vch->name, "CCD-input");
742
                vch->type = VIDEO_TYPE_CAMERA;
743
                return 0;
744
        }
745
        case VIDIOCSCHAN:
746
        {
747
                struct video_channel *vch = arg;
748
                if(vch->channel != 0)
749
                        return -EINVAL;
750
                return 0;
751
        }
752
        case VIDIOCGTUNER:
753
        {
754
                struct video_tuner *vtune = arg;
755
                if(vtune->tuner != 0)
756
                        return -EINVAL;
757
                strcpy(vtune->name, "no tuner");
758
                vtune->rangelow = 0;
759
                vtune->rangehigh = 0;
760
                vtune->flags = VIDEO_TUNER_NORM;
761
                vtune->mode = VIDEO_MODE_AUTO;
762
                vtune->signal = 0xffff;
763
                return 0;
764
        }
765
        case VIDIOCSTUNER:
766
        {
767
                struct video_tuner *vtune = arg;
768
                if (vtune->tuner != 0)
769
                        return -EINVAL;
770
                if (vtune->mode != VIDEO_MODE_AUTO)
771
                        return -EINVAL;
772
                return 0;
773
        }
774
        case VIDIOCGPICT:
775
        {
776
                struct video_picture vpic = {
777
                        cam->brightness << 8,   // brightness
778
                        (cam->hue + 128) << 8,  // hue
779
                        cam->color << 9,        // color
780
                        cam->contrast << 9,     // contrast
781
                        0x8000,                 // whiteness
782
                        16, VIDEO_PALETTE_YUV422// bpp, palette format
783
                };
784
                struct video_picture *pic = arg;
785
                *pic = vpic;
786
                return 0;
787
        }
788
        case VIDIOCSPICT:
789
        {
790
                struct video_picture *vpic = arg;
791
                if (vpic->depth != 16 || (vpic->palette != VIDEO_PALETTE_YUV422 && vpic->palette != VIDEO_PALETTE_YUYV))
792
                        return -EINVAL;
793
 
794
                cam->brightness = vpic->brightness >> 8;
795
                cam->hue = (vpic->hue >> 8) - 128;
796
                cam->color = vpic->colour >> 9;
797
                cam->contrast = vpic->contrast >> 9;
798
 
799
                w9966_pdev_claim(cam);
800
 
801
                if (
802
                        w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 ||
803
                        w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 ||
804
                        w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 ||
805
                        w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1
806
                ) {
807
                        w9966_pdev_release(cam);
808
                        return -EIO;
809
                }
810
 
811
                w9966_pdev_release(cam);
812
                return 0;
813
        }
814
        case VIDIOCSWIN:
815
        {
816
                int ret;
817
                struct video_window *vwin = arg;
818
 
819
                if (vwin->flags != 0)
820
                        return -EINVAL;
821
                if (vwin->clipcount != 0)
822
                        return -EINVAL;
823
                if (vwin->width < 2 || vwin->width > W9966_WND_MAX_W)
824
                        return -EINVAL;
825
                if (vwin->height < 1 || vwin->height > W9966_WND_MAX_H)
826
                        return -EINVAL;
827
 
828
                // Update camera regs
829
                w9966_pdev_claim(cam);
830
                ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin->width, vwin->height);
831
                w9966_pdev_release(cam);
832
 
833
                if (ret != 0) {
834
                        DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
835
                        return -EIO;
836
                }
837
 
838
                return 0;
839
        }
840
        case VIDIOCGWIN:
841
        {
842
                struct video_window *vwin = arg;
843
                memset(vwin, 0, sizeof(*vwin));
844
                vwin->width = cam->width;
845
                vwin->height = cam->height;
846
                return 0;
847
        }
848
        // Unimplemented
849
        case VIDIOCCAPTURE:
850
        case VIDIOCGFBUF:
851
        case VIDIOCSFBUF:
852
        case VIDIOCKEY:
853
        case VIDIOCGFREQ:
854
        case VIDIOCSFREQ:
855
        case VIDIOCGAUDIO:
856
        case VIDIOCSAUDIO:
857
                return -EINVAL;
858
        default:
859
                return -ENOIOCTLCMD;
860
        }
861
        return 0;
862
}
863
 
864
static int w9966_v4l_ioctl(struct inode *inode, struct file *file,
865
                           unsigned int cmd, unsigned long arg)
866
{
867
        return video_usercopy(inode, file, cmd, arg, w9966_v4l_do_ioctl);
868
}
869
 
870
// Capture data
871
static ssize_t w9966_v4l_read(struct file *file, char  __user *buf,
872
                              size_t count, loff_t *ppos)
873
{
874
        struct video_device *vdev = video_devdata(file);
875
        struct w9966_dev *cam = vdev->priv;
876
        unsigned char addr = 0xa0;      // ECP, read, CCD-transfer, 00000
877
        unsigned char __user *dest = (unsigned char __user *)buf;
878
        unsigned long dleft = count;
879
        unsigned char *tbuf;
880
 
881
        // Why would anyone want more than this??
882
        if (count > cam->width * cam->height * 2)
883
                return -EINVAL;
884
 
885
        w9966_pdev_claim(cam);
886
        w9966_wReg(cam, 0x00, 0x02);    // Reset ECP-FIFO buffer
887
        w9966_wReg(cam, 0x00, 0x00);    // Return to normal operation
888
        w9966_wReg(cam, 0x01, 0x98);    // Enable capture
889
 
890
        // write special capture-addr and negotiate into data transfer
891
        if (
892
                (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0   )||
893
                (parport_write(cam->pport, &addr, 1) != 1                                               )||
894
                (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0   )
895
        ) {
896
                w9966_pdev_release(cam);
897
                return -EFAULT;
898
        }
899
 
900
        tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL);
901
        if (tbuf == NULL) {
902
                count = -ENOMEM;
903
                goto out;
904
        }
905
 
906
        while(dleft > 0)
907
        {
908
                unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
909
 
910
                if (parport_read(cam->pport, tbuf, tsize) < tsize) {
911
                        count = -EFAULT;
912
                        goto out;
913
                }
914
                if (copy_to_user(dest, tbuf, tsize) != 0) {
915
                        count = -EFAULT;
916
                        goto out;
917
                }
918
                dest += tsize;
919
                dleft -= tsize;
920
        }
921
 
922
        w9966_wReg(cam, 0x01, 0x18);    // Disable capture
923
 
924
out:
925
        kfree(tbuf);
926
        w9966_pdev_release(cam);
927
 
928
        return count;
929
}
930
 
931
 
932
// Called once for every parport on init
933
static void w9966_attach(struct parport *port)
934
{
935
        int i;
936
 
937
        for (i = 0; i < W9966_MAXCAMS; i++)
938
        {
939
                if (w9966_cams[i].dev_state != 0)        // Cam is already assigned
940
                        continue;
941
                if (
942
                        strcmp(pardev[i], "aggressive") == 0 ||
943
                        strcmp(pardev[i], port->name) == 0
944
                ) {
945
                        if (w9966_init(&w9966_cams[i], port) != 0)
946
                        w9966_term(&w9966_cams[i]);
947
                        break;  // return
948
                }
949
        }
950
}
951
 
952
// Called once for every parport on termination
953
static void w9966_detach(struct parport *port)
954
{
955
        int i;
956
        for (i = 0; i < W9966_MAXCAMS; i++)
957
        if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
958
                w9966_term(&w9966_cams[i]);
959
}
960
 
961
 
962
static struct parport_driver w9966_ppd = {
963
        .name = W9966_DRIVERNAME,
964
        .attach = w9966_attach,
965
        .detach = w9966_detach,
966
};
967
 
968
// Module entry point
969
static int __init w9966_mod_init(void)
970
{
971
        int i;
972
        for (i = 0; i < W9966_MAXCAMS; i++)
973
                w9966_cams[i].dev_state = 0;
974
 
975
        return parport_register_driver(&w9966_ppd);
976
}
977
 
978
// Module cleanup
979
static void __exit w9966_mod_term(void)
980
{
981
        parport_unregister_driver(&w9966_ppd);
982
}
983
 
984
module_init(w9966_mod_init);
985
module_exit(w9966_mod_term);

powered by: WebSVN 2.1.0

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