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

Subversion Repositories or1k

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

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

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

powered by: WebSVN 2.1.0

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