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