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

Subversion Repositories test_project

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *      Video4Linux Colour QuickCam driver
3
 *      Copyright 1997-2000 Philip Blundell <philb@gnu.org>
4
 *
5
 *    Module parameters:
6
 *
7
 *      parport=auto      -- probe all parports (default)
8
 *      parport=0         -- parport0 becomes qcam1
9
 *      parport=2,0,1     -- parports 2,0,1 are tried in that order
10
 *
11
 *      probe=0           -- do no probing, assume camera is present
12
 *      probe=1           -- use IEEE-1284 autoprobe data only (default)
13
 *      probe=2           -- probe aggressively for cameras
14
 *
15
 *      force_rgb=1       -- force data format to RGB (default is BGR)
16
 *
17
 * The parport parameter controls which parports will be scanned.
18
 * Scanning all parports causes some printers to print a garbage page.
19
 *       -- March 14, 1999  Billy Donahue <billy@escape.com>
20
 *
21
 * Fixed data format to BGR, added force_rgb parameter. Added missing
22
 * parport_unregister_driver() on module removal.
23
 *       -- May 28, 2000  Claudio Matsuoka <claudio@conectiva.com>
24
 */
25
 
26
#include <linux/module.h>
27
#include <linux/delay.h>
28
#include <linux/errno.h>
29
#include <linux/fs.h>
30
#include <linux/init.h>
31
#include <linux/kernel.h>
32
#include <linux/slab.h>
33
#include <linux/mm.h>
34
#include <linux/parport.h>
35
#include <linux/sched.h>
36
#include <linux/videodev.h>
37
#include <media/v4l2-common.h>
38
#include <linux/mutex.h>
39
 
40
#include <asm/uaccess.h>
41
 
42
struct qcam_device {
43
        struct video_device vdev;
44
        struct pardevice *pdev;
45
        struct parport *pport;
46
        int width, height;
47
        int ccd_width, ccd_height;
48
        int mode;
49
        int contrast, brightness, whitebal;
50
        int top, left;
51
        unsigned int bidirectional;
52
        struct mutex lock;
53
};
54
 
55
/* cameras maximum */
56
#define MAX_CAMS 4
57
 
58
/* The three possible QuickCam modes */
59
#define QC_MILLIONS     0x18
60
#define QC_BILLIONS     0x10
61
#define QC_THOUSANDS    0x08    /* with VIDEC compression (not supported) */
62
 
63
/* The three possible decimations */
64
#define QC_DECIMATION_1         0
65
#define QC_DECIMATION_2         2
66
#define QC_DECIMATION_4         4
67
 
68
#define BANNER "Colour QuickCam for Video4Linux v0.05"
69
 
70
static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
71
static int probe = 2;
72
static int force_rgb = 0;
73
static int video_nr = -1;
74
 
75
static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
76
{
77
        /* note: the QC specs refer to the PCAck pin by voltage, not
78
           software level.  PC ports have builtin inverters. */
79
        parport_frob_control(qcam->pport, 8, i?8:0);
80
}
81
 
82
static inline unsigned int qcam_ready1(struct qcam_device *qcam)
83
{
84
        return (parport_read_status(qcam->pport) & 0x8)?1:0;
85
}
86
 
87
static inline unsigned int qcam_ready2(struct qcam_device *qcam)
88
{
89
        return (parport_read_data(qcam->pport) & 0x1)?1:0;
90
}
91
 
92
static unsigned int qcam_await_ready1(struct qcam_device *qcam,
93
                                             int value)
94
{
95
        unsigned long oldjiffies = jiffies;
96
        unsigned int i;
97
 
98
        for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
99
                if (qcam_ready1(qcam) == value)
100
                        return 0;
101
 
102
        /* If the camera didn't respond within 1/25 second, poll slowly
103
           for a while. */
104
        for (i = 0; i < 50; i++)
105
        {
106
                if (qcam_ready1(qcam) == value)
107
                        return 0;
108
                msleep_interruptible(100);
109
        }
110
 
111
        /* Probably somebody pulled the plug out.  Not much we can do. */
112
        printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value,
113
               parport_read_status(qcam->pport),
114
               parport_read_control(qcam->pport));
115
        return 1;
116
}
117
 
118
static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
119
{
120
        unsigned long oldjiffies = jiffies;
121
        unsigned int i;
122
 
123
        for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
124
                if (qcam_ready2(qcam) == value)
125
                        return 0;
126
 
127
        /* If the camera didn't respond within 1/25 second, poll slowly
128
           for a while. */
129
        for (i = 0; i < 50; i++)
130
        {
131
                if (qcam_ready2(qcam) == value)
132
                        return 0;
133
                msleep_interruptible(100);
134
        }
135
 
136
        /* Probably somebody pulled the plug out.  Not much we can do. */
137
        printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value,
138
               parport_read_status(qcam->pport),
139
               parport_read_control(qcam->pport),
140
               parport_read_data(qcam->pport));
141
        return 1;
142
}
143
 
144
static int qcam_read_data(struct qcam_device *qcam)
145
{
146
        unsigned int idata;
147
        qcam_set_ack(qcam, 0);
148
        if (qcam_await_ready1(qcam, 1)) return -1;
149
        idata = parport_read_status(qcam->pport) & 0xf0;
150
        qcam_set_ack(qcam, 1);
151
        if (qcam_await_ready1(qcam, 0)) return -1;
152
        idata |= (parport_read_status(qcam->pport) >> 4);
153
        return idata;
154
}
155
 
156
static int qcam_write_data(struct qcam_device *qcam, unsigned int data)
157
{
158
        unsigned int idata;
159
        parport_write_data(qcam->pport, data);
160
        idata = qcam_read_data(qcam);
161
        if (data != idata)
162
        {
163
                printk(KERN_WARNING "cqcam: sent %x but received %x\n", data,
164
                       idata);
165
                return 1;
166
        }
167
        return 0;
168
}
169
 
170
static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data)
171
{
172
        if (qcam_write_data(qcam, cmd))
173
                return -1;
174
        if (qcam_write_data(qcam, data))
175
                return -1;
176
        return 0;
177
}
178
 
179
static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd)
180
{
181
        if (qcam_write_data(qcam, cmd))
182
                return -1;
183
        return qcam_read_data(qcam);
184
}
185
 
186
static int qc_detect(struct qcam_device *qcam)
187
{
188
        unsigned int stat, ostat, i, count = 0;
189
 
190
        /* The probe routine below is not very reliable.  The IEEE-1284
191
           probe takes precedence. */
192
        /* XXX Currently parport provides no way to distinguish between
193
           "the IEEE probe was not done" and "the probe was done, but
194
           no device was found".  Fix this one day. */
195
        if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA
196
            && qcam->pport->probe_info[0].model
197
            && !strcmp(qcam->pdev->port->probe_info[0].model,
198
                       "Color QuickCam 2.0")) {
199
                printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
200
                return 1;
201
        }
202
 
203
        if (probe < 2)
204
                return 0;
205
 
206
        parport_write_control(qcam->pport, 0xc);
207
 
208
        /* look for a heartbeat */
209
        ostat = stat = parport_read_status(qcam->pport);
210
        for (i=0; i<250; i++)
211
        {
212
                mdelay(1);
213
                stat = parport_read_status(qcam->pport);
214
                if (ostat != stat)
215
                {
216
                        if (++count >= 3) return 1;
217
                        ostat = stat;
218
                }
219
        }
220
 
221
        /* Reset the camera and try again */
222
        parport_write_control(qcam->pport, 0xc);
223
        parport_write_control(qcam->pport, 0x8);
224
        mdelay(1);
225
        parport_write_control(qcam->pport, 0xc);
226
        mdelay(1);
227
        count = 0;
228
 
229
        ostat = stat = parport_read_status(qcam->pport);
230
        for (i=0; i<250; i++)
231
        {
232
                mdelay(1);
233
                stat = parport_read_status(qcam->pport);
234
                if (ostat != stat)
235
                {
236
                        if (++count >= 3) return 1;
237
                        ostat = stat;
238
                }
239
        }
240
 
241
        /* no (or flatline) camera, give up */
242
        return 0;
243
}
244
 
245
static void qc_reset(struct qcam_device *qcam)
246
{
247
        parport_write_control(qcam->pport, 0xc);
248
        parport_write_control(qcam->pport, 0x8);
249
        mdelay(1);
250
        parport_write_control(qcam->pport, 0xc);
251
        mdelay(1);
252
}
253
 
254
/* Reset the QuickCam and program for brightness, contrast,
255
 * white-balance, and resolution. */
256
 
257
static void qc_setup(struct qcam_device *q)
258
{
259
        qc_reset(q);
260
 
261
        /* Set the brightness.  */
262
        qcam_set(q, 11, q->brightness);
263
 
264
        /* Set the height and width.  These refer to the actual
265
           CCD area *before* applying the selected decimation.  */
266
        qcam_set(q, 17, q->ccd_height);
267
        qcam_set(q, 19, q->ccd_width / 2);
268
 
269
        /* Set top and left.  */
270
        qcam_set(q, 0xd, q->top);
271
        qcam_set(q, 0xf, q->left);
272
 
273
        /* Set contrast and white balance.  */
274
        qcam_set(q, 0x19, q->contrast);
275
        qcam_set(q, 0x1f, q->whitebal);
276
 
277
        /* Set the speed.  */
278
        qcam_set(q, 45, 2);
279
}
280
 
281
/* Read some bytes from the camera and put them in the buffer.
282
   nbytes should be a multiple of 3, because bidirectional mode gives
283
   us three bytes at a time.  */
284
 
285
static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes)
286
{
287
        unsigned int bytes = 0;
288
 
289
        qcam_set_ack(q, 0);
290
        if (q->bidirectional)
291
        {
292
                /* It's a bidirectional port */
293
                while (bytes < nbytes)
294
                {
295
                        unsigned int lo1, hi1, lo2, hi2;
296
                        unsigned char r, g, b;
297
 
298
                        if (qcam_await_ready2(q, 1)) return bytes;
299
                        lo1 = parport_read_data(q->pport) >> 1;
300
                        hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
301
                        qcam_set_ack(q, 1);
302
                        if (qcam_await_ready2(q, 0)) return bytes;
303
                        lo2 = parport_read_data(q->pport) >> 1;
304
                        hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
305
                        qcam_set_ack(q, 0);
306
                        r = (lo1 | ((hi1 & 1)<<7));
307
                        g = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1);
308
                        b = (lo2 | ((hi2 & 1)<<7));
309
                        if (force_rgb) {
310
                                buf[bytes++] = r;
311
                                buf[bytes++] = g;
312
                                buf[bytes++] = b;
313
                        } else {
314
                                buf[bytes++] = b;
315
                                buf[bytes++] = g;
316
                                buf[bytes++] = r;
317
                        }
318
                }
319
        }
320
        else
321
        {
322
                /* It's a unidirectional port */
323
                int i = 0, n = bytes;
324
                unsigned char rgb[3];
325
 
326
                while (bytes < nbytes)
327
                {
328
                        unsigned int hi, lo;
329
 
330
                        if (qcam_await_ready1(q, 1)) return bytes;
331
                        hi = (parport_read_status(q->pport) & 0xf0);
332
                        qcam_set_ack(q, 1);
333
                        if (qcam_await_ready1(q, 0)) return bytes;
334
                        lo = (parport_read_status(q->pport) & 0xf0);
335
                        qcam_set_ack(q, 0);
336
                        /* flip some bits */
337
                        rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
338
                        if (i >= 2) {
339
get_fragment:
340
                                if (force_rgb) {
341
                                        buf[n++] = rgb[0];
342
                                        buf[n++] = rgb[1];
343
                                        buf[n++] = rgb[2];
344
                                } else {
345
                                        buf[n++] = rgb[2];
346
                                        buf[n++] = rgb[1];
347
                                        buf[n++] = rgb[0];
348
                                }
349
                        }
350
                }
351
                if (i) {
352
                        i = 0;
353
                        goto get_fragment;
354
                }
355
        }
356
        return bytes;
357
}
358
 
359
#define BUFSZ   150
360
 
361
static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len)
362
{
363
        unsigned lines, pixelsperline, bitsperxfer;
364
        unsigned int is_bi_dir = q->bidirectional;
365
        size_t wantlen, outptr = 0;
366
        char tmpbuf[BUFSZ];
367
 
368
        if (!access_ok(VERIFY_WRITE, buf, len))
369
                return -EFAULT;
370
 
371
        /* Wait for camera to become ready */
372
        for (;;)
373
        {
374
                int i = qcam_get(q, 41);
375
                if (i == -1) {
376
                        qc_setup(q);
377
                        return -EIO;
378
                }
379
                if ((i & 0x80) == 0)
380
                        break;
381
                else
382
                        schedule();
383
        }
384
 
385
        if (qcam_set(q, 7, (q->mode | (is_bi_dir?1:0)) + 1))
386
                return -EIO;
387
 
388
        lines = q->height;
389
        pixelsperline = q->width;
390
        bitsperxfer = (is_bi_dir) ? 24 : 8;
391
 
392
        if (is_bi_dir)
393
        {
394
                /* Turn the port around */
395
                parport_data_reverse(q->pport);
396
                mdelay(3);
397
                qcam_set_ack(q, 0);
398
                if (qcam_await_ready1(q, 1)) {
399
                        qc_setup(q);
400
                        return -EIO;
401
                }
402
                qcam_set_ack(q, 1);
403
                if (qcam_await_ready1(q, 0)) {
404
                        qc_setup(q);
405
                        return -EIO;
406
                }
407
        }
408
 
409
        wantlen = lines * pixelsperline * 24 / 8;
410
 
411
        while (wantlen)
412
        {
413
                size_t t, s;
414
                s = (wantlen > BUFSZ)?BUFSZ:wantlen;
415
                t = qcam_read_bytes(q, tmpbuf, s);
416
                if (outptr < len)
417
                {
418
                        size_t sz = len - outptr;
419
                        if (sz > t) sz = t;
420
                        if (__copy_to_user(buf+outptr, tmpbuf, sz))
421
                                break;
422
                        outptr += sz;
423
                }
424
                wantlen -= t;
425
                if (t < s)
426
                        break;
427
                cond_resched();
428
        }
429
 
430
        len = outptr;
431
 
432
        if (wantlen)
433
        {
434
                printk("qcam: short read.\n");
435
                if (is_bi_dir)
436
                        parport_data_forward(q->pport);
437
                qc_setup(q);
438
                return len;
439
        }
440
 
441
        if (is_bi_dir)
442
        {
443
                int l;
444
                do {
445
                        l = qcam_read_bytes(q, tmpbuf, 3);
446
                        cond_resched();
447
                } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
448
                if (force_rgb) {
449
                        if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
450
                                printk("qcam: bad EOF\n");
451
                } else {
452
                        if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
453
                                printk("qcam: bad EOF\n");
454
                }
455
                qcam_set_ack(q, 0);
456
                if (qcam_await_ready1(q, 1))
457
                {
458
                        printk("qcam: no ack after EOF\n");
459
                        parport_data_forward(q->pport);
460
                        qc_setup(q);
461
                        return len;
462
                }
463
                parport_data_forward(q->pport);
464
                mdelay(3);
465
                qcam_set_ack(q, 1);
466
                if (qcam_await_ready1(q, 0))
467
                {
468
                        printk("qcam: no ack to port turnaround\n");
469
                        qc_setup(q);
470
                        return len;
471
                }
472
        }
473
        else
474
        {
475
                int l;
476
                do {
477
                        l = qcam_read_bytes(q, tmpbuf, 1);
478
                        cond_resched();
479
                } while (l && tmpbuf[0] == 0x7e);
480
                l = qcam_read_bytes(q, tmpbuf+1, 2);
481
                if (force_rgb) {
482
                        if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
483
                                printk("qcam: bad EOF\n");
484
                } else {
485
                        if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
486
                                printk("qcam: bad EOF\n");
487
                }
488
        }
489
 
490
        qcam_write_data(q, 0);
491
        return len;
492
}
493
 
494
/*
495
 *      Video4linux interfacing
496
 */
497
 
498
static int qcam_do_ioctl(struct inode *inode, struct file *file,
499
                         unsigned int cmd, void *arg)
500
{
501
        struct video_device *dev = video_devdata(file);
502
        struct qcam_device *qcam=(struct qcam_device *)dev;
503
 
504
        switch(cmd)
505
        {
506
                case VIDIOCGCAP:
507
                {
508
                        struct video_capability *b = arg;
509
                        strcpy(b->name, "Quickcam");
510
                        b->type = VID_TYPE_CAPTURE|VID_TYPE_SCALES;
511
                        b->channels = 1;
512
                        b->audios = 0;
513
                        b->maxwidth = 320;
514
                        b->maxheight = 240;
515
                        b->minwidth = 80;
516
                        b->minheight = 60;
517
                        return 0;
518
                }
519
                case VIDIOCGCHAN:
520
                {
521
                        struct video_channel *v = arg;
522
                        if(v->channel!=0)
523
                                return -EINVAL;
524
                        v->flags=0;
525
                        v->tuners=0;
526
                        /* Good question.. its composite or SVHS so.. */
527
                        v->type = VIDEO_TYPE_CAMERA;
528
                        strcpy(v->name, "Camera");
529
                        return 0;
530
                }
531
                case VIDIOCSCHAN:
532
                {
533
                        struct video_channel *v = arg;
534
                        if(v->channel!=0)
535
                                return -EINVAL;
536
                        return 0;
537
                }
538
                case VIDIOCGTUNER:
539
                {
540
                        struct video_tuner *v = arg;
541
                        if(v->tuner)
542
                                return -EINVAL;
543
                        memset(v,0,sizeof(*v));
544
                        strcpy(v->name, "Format");
545
                        v->mode = VIDEO_MODE_AUTO;
546
                        return 0;
547
                }
548
                case VIDIOCSTUNER:
549
                {
550
                        struct video_tuner *v = arg;
551
                        if(v->tuner)
552
                                return -EINVAL;
553
                        if(v->mode!=VIDEO_MODE_AUTO)
554
                                return -EINVAL;
555
                        return 0;
556
                }
557
                case VIDIOCGPICT:
558
                {
559
                        struct video_picture *p = arg;
560
                        p->colour=0x8000;
561
                        p->hue=0x8000;
562
                        p->brightness=qcam->brightness<<8;
563
                        p->contrast=qcam->contrast<<8;
564
                        p->whiteness=qcam->whitebal<<8;
565
                        p->depth=24;
566
                        p->palette=VIDEO_PALETTE_RGB24;
567
                        return 0;
568
                }
569
                case VIDIOCSPICT:
570
                {
571
                        struct video_picture *p = arg;
572
 
573
                        /*
574
                         *      Sanity check args
575
                         */
576
                        if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24)
577
                                return -EINVAL;
578
 
579
                        /*
580
                         *      Now load the camera.
581
                         */
582
                        qcam->brightness = p->brightness>>8;
583
                        qcam->contrast = p->contrast>>8;
584
                        qcam->whitebal = p->whiteness>>8;
585
 
586
                        mutex_lock(&qcam->lock);
587
                        parport_claim_or_block(qcam->pdev);
588
                        qc_setup(qcam);
589
                        parport_release(qcam->pdev);
590
                        mutex_unlock(&qcam->lock);
591
                        return 0;
592
                }
593
                case VIDIOCSWIN:
594
                {
595
                        struct video_window *vw = arg;
596
 
597
                        if(vw->flags)
598
                                return -EINVAL;
599
                        if(vw->clipcount)
600
                                return -EINVAL;
601
                        if(vw->height<60||vw->height>240)
602
                                return -EINVAL;
603
                        if(vw->width<80||vw->width>320)
604
                                return -EINVAL;
605
 
606
                        qcam->width = 80;
607
                        qcam->height = 60;
608
                        qcam->mode = QC_DECIMATION_4;
609
 
610
                        if(vw->width>=160 && vw->height>=120)
611
                        {
612
                                qcam->width = 160;
613
                                qcam->height = 120;
614
                                qcam->mode = QC_DECIMATION_2;
615
                        }
616
                        if(vw->width>=320 && vw->height>=240)
617
                        {
618
                                qcam->width = 320;
619
                                qcam->height = 240;
620
                                qcam->mode = QC_DECIMATION_1;
621
                        }
622
                        qcam->mode |= QC_MILLIONS;
623
#if 0
624
                        if(vw->width>=640 && vw->height>=480)
625
                        {
626
                                qcam->width = 640;
627
                                qcam->height = 480;
628
                                qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
629
                        }
630
#endif
631
                        /* Ok we figured out what to use from our
632
                           wide choice */
633
                        mutex_lock(&qcam->lock);
634
                        parport_claim_or_block(qcam->pdev);
635
                        qc_setup(qcam);
636
                        parport_release(qcam->pdev);
637
                        mutex_unlock(&qcam->lock);
638
                        return 0;
639
                }
640
                case VIDIOCGWIN:
641
                {
642
                        struct video_window *vw = arg;
643
                        memset(vw, 0, sizeof(*vw));
644
                        vw->width=qcam->width;
645
                        vw->height=qcam->height;
646
                        return 0;
647
                }
648
                case VIDIOCKEY:
649
                        return 0;
650
                case VIDIOCCAPTURE:
651
                case VIDIOCGFBUF:
652
                case VIDIOCSFBUF:
653
                case VIDIOCGFREQ:
654
                case VIDIOCSFREQ:
655
                case VIDIOCGAUDIO:
656
                case VIDIOCSAUDIO:
657
                        return -EINVAL;
658
                default:
659
                        return -ENOIOCTLCMD;
660
        }
661
        return 0;
662
}
663
 
664
static int qcam_ioctl(struct inode *inode, struct file *file,
665
                     unsigned int cmd, unsigned long arg)
666
{
667
        return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl);
668
}
669
 
670
static ssize_t qcam_read(struct file *file, char __user *buf,
671
                         size_t count, loff_t *ppos)
672
{
673
        struct video_device *v = video_devdata(file);
674
        struct qcam_device *qcam=(struct qcam_device *)v;
675
        int len;
676
 
677
        mutex_lock(&qcam->lock);
678
        parport_claim_or_block(qcam->pdev);
679
        /* Probably should have a semaphore against multiple users */
680
        len = qc_capture(qcam, buf,count);
681
        parport_release(qcam->pdev);
682
        mutex_unlock(&qcam->lock);
683
        return len;
684
}
685
 
686
/* video device template */
687
static const struct file_operations qcam_fops = {
688
        .owner          = THIS_MODULE,
689
        .open           = video_exclusive_open,
690
        .release        = video_exclusive_release,
691
        .ioctl          = qcam_ioctl,
692
        .compat_ioctl   = v4l_compat_ioctl32,
693
        .read           = qcam_read,
694
        .llseek         = no_llseek,
695
};
696
 
697
static struct video_device qcam_template=
698
{
699
        .owner          = THIS_MODULE,
700
        .name           = "Colour QuickCam",
701
        .type           = VID_TYPE_CAPTURE,
702
        .fops           = &qcam_fops,
703
};
704
 
705
/* Initialize the QuickCam driver control structure. */
706
 
707
static struct qcam_device *qcam_init(struct parport *port)
708
{
709
        struct qcam_device *q;
710
 
711
        q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
712
        if(q==NULL)
713
                return NULL;
714
 
715
        q->pport = port;
716
        q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
717
                                          NULL, 0, NULL);
718
 
719
        q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0;
720
 
721
        if (q->pdev == NULL)
722
        {
723
                printk(KERN_ERR "c-qcam: couldn't register for %s.\n",
724
                       port->name);
725
                kfree(q);
726
                return NULL;
727
        }
728
 
729
        memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
730
 
731
        mutex_init(&q->lock);
732
        q->width = q->ccd_width = 320;
733
        q->height = q->ccd_height = 240;
734
        q->mode = QC_MILLIONS | QC_DECIMATION_1;
735
        q->contrast = 192;
736
        q->brightness = 240;
737
        q->whitebal = 128;
738
        q->top = 1;
739
        q->left = 14;
740
        return q;
741
}
742
 
743
static struct qcam_device *qcams[MAX_CAMS];
744
static unsigned int num_cams = 0;
745
 
746
static int init_cqcam(struct parport *port)
747
{
748
        struct qcam_device *qcam;
749
 
750
        if (parport[0] != -1)
751
        {
752
                /* The user gave specific instructions */
753
                int i, found = 0;
754
                for (i = 0; i < MAX_CAMS && parport[i] != -1; i++)
755
                {
756
                        if (parport[0] == port->number)
757
                                found = 1;
758
                }
759
                if (!found)
760
                        return -ENODEV;
761
        }
762
 
763
        if (num_cams == MAX_CAMS)
764
                return -ENOSPC;
765
 
766
        qcam = qcam_init(port);
767
        if (qcam==NULL)
768
                return -ENODEV;
769
 
770
        parport_claim_or_block(qcam->pdev);
771
 
772
        qc_reset(qcam);
773
 
774
        if (probe && qc_detect(qcam)==0)
775
        {
776
                parport_release(qcam->pdev);
777
                parport_unregister_device(qcam->pdev);
778
                kfree(qcam);
779
                return -ENODEV;
780
        }
781
 
782
        qc_setup(qcam);
783
 
784
        parport_release(qcam->pdev);
785
 
786
        if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
787
        {
788
                printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
789
                       qcam->pport->name);
790
                parport_unregister_device(qcam->pdev);
791
                kfree(qcam);
792
                return -ENODEV;
793
        }
794
 
795
        printk(KERN_INFO "video%d: Colour QuickCam found on %s\n",
796
               qcam->vdev.minor, qcam->pport->name);
797
 
798
        qcams[num_cams++] = qcam;
799
 
800
        return 0;
801
}
802
 
803
static void close_cqcam(struct qcam_device *qcam)
804
{
805
        video_unregister_device(&qcam->vdev);
806
        parport_unregister_device(qcam->pdev);
807
        kfree(qcam);
808
}
809
 
810
static void cq_attach(struct parport *port)
811
{
812
        init_cqcam(port);
813
}
814
 
815
static void cq_detach(struct parport *port)
816
{
817
        /* Write this some day. */
818
}
819
 
820
static struct parport_driver cqcam_driver = {
821
        .name = "cqcam",
822
        .attach = cq_attach,
823
        .detach = cq_detach,
824
};
825
 
826
static int __init cqcam_init (void)
827
{
828
        printk(BANNER "\n");
829
 
830
        return parport_register_driver(&cqcam_driver);
831
}
832
 
833
static void __exit cqcam_cleanup (void)
834
{
835
        unsigned int i;
836
 
837
        for (i = 0; i < num_cams; i++)
838
                close_cqcam(qcams[i]);
839
 
840
        parport_unregister_driver(&cqcam_driver);
841
}
842
 
843
MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
844
MODULE_DESCRIPTION(BANNER);
845
MODULE_LICENSE("GPL");
846
 
847
/* FIXME: parport=auto would never have worked, surely? --RR */
848
MODULE_PARM_DESC(parport ,"parport=<auto|n[,n]...> for port detection method\n\
849
probe=<0|1|2> for camera detection method\n\
850
force_rgb=<0|1> for RGB data format (default BGR)");
851
module_param_array(parport, int, NULL, 0);
852
module_param(probe, int, 0);
853
module_param(force_rgb, bool, 0);
854
module_param(video_nr, int, 0);
855
 
856
module_init(cqcam_init);
857
module_exit(cqcam_cleanup);

powered by: WebSVN 2.1.0

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