blob: 7f6c6b4bec10e7f3470d8452e1ee71b9cd90ab0e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030019 * -- March 14, 1999 Billy Donahue <billy@escape.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 *
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>
Mauro Carvalho Chehab5e87efa2006-06-05 10:26:32 -030037#include <media/v4l2-common.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030038#include <media/v4l2-ioctl.h>
Ingo Molnar3593cab2006-02-07 06:49:14 -020039#include <linux/mutex.h>
Julia Lawall168c6262008-04-16 16:13:15 -030040#include <linux/jiffies.h>
Ingo Molnar3593cab2006-02-07 06:49:14 -020041
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/uaccess.h>
43
44struct qcam_device {
45 struct video_device vdev;
46 struct pardevice *pdev;
47 struct parport *pport;
48 int width, height;
49 int ccd_width, ccd_height;
50 int mode;
51 int contrast, brightness, whitebal;
52 int top, left;
53 unsigned int bidirectional;
Ingo Molnar3593cab2006-02-07 06:49:14 -020054 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -070055};
56
57/* cameras maximum */
58#define MAX_CAMS 4
59
60/* The three possible QuickCam modes */
61#define QC_MILLIONS 0x18
62#define QC_BILLIONS 0x10
63#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */
64
65/* The three possible decimations */
66#define QC_DECIMATION_1 0
67#define QC_DECIMATION_2 2
68#define QC_DECIMATION_4 4
69
70#define BANNER "Colour QuickCam for Video4Linux v0.05"
71
72static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
73static int probe = 2;
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030074static int force_rgb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075static int video_nr = -1;
76
77static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
78{
79 /* note: the QC specs refer to the PCAck pin by voltage, not
80 software level. PC ports have builtin inverters. */
81 parport_frob_control(qcam->pport, 8, i?8:0);
82}
83
84static inline unsigned int qcam_ready1(struct qcam_device *qcam)
85{
86 return (parport_read_status(qcam->pport) & 0x8)?1:0;
87}
88
89static inline unsigned int qcam_ready2(struct qcam_device *qcam)
90{
91 return (parport_read_data(qcam->pport) & 0x1)?1:0;
92}
93
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030094static unsigned int qcam_await_ready1(struct qcam_device *qcam,
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 int value)
96{
97 unsigned long oldjiffies = jiffies;
98 unsigned int i;
99
Julia Lawall168c6262008-04-16 16:13:15 -0300100 for (oldjiffies = jiffies;
101 time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 if (qcam_ready1(qcam) == value)
103 return 0;
104
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300105 /* If the camera didn't respond within 1/25 second, poll slowly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 for a while. */
107 for (i = 0; i < 50; i++)
108 {
109 if (qcam_ready1(qcam) == value)
110 return 0;
111 msleep_interruptible(100);
112 }
113
114 /* Probably somebody pulled the plug out. Not much we can do. */
115 printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value,
116 parport_read_status(qcam->pport),
117 parport_read_control(qcam->pport));
118 return 1;
119}
120
121static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
122{
123 unsigned long oldjiffies = jiffies;
124 unsigned int i;
125
Julia Lawall168c6262008-04-16 16:13:15 -0300126 for (oldjiffies = jiffies;
127 time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 if (qcam_ready2(qcam) == value)
129 return 0;
130
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300131 /* If the camera didn't respond within 1/25 second, poll slowly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 for a while. */
133 for (i = 0; i < 50; i++)
134 {
135 if (qcam_ready2(qcam) == value)
136 return 0;
137 msleep_interruptible(100);
138 }
139
140 /* Probably somebody pulled the plug out. Not much we can do. */
141 printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value,
142 parport_read_status(qcam->pport),
143 parport_read_control(qcam->pport),
144 parport_read_data(qcam->pport));
145 return 1;
146}
147
148static int qcam_read_data(struct qcam_device *qcam)
149{
150 unsigned int idata;
151 qcam_set_ack(qcam, 0);
152 if (qcam_await_ready1(qcam, 1)) return -1;
153 idata = parport_read_status(qcam->pport) & 0xf0;
154 qcam_set_ack(qcam, 1);
155 if (qcam_await_ready1(qcam, 0)) return -1;
156 idata |= (parport_read_status(qcam->pport) >> 4);
157 return idata;
158}
159
160static int qcam_write_data(struct qcam_device *qcam, unsigned int data)
161{
162 unsigned int idata;
163 parport_write_data(qcam->pport, data);
164 idata = qcam_read_data(qcam);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300165 if (data != idata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 {
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300167 printk(KERN_WARNING "cqcam: sent %x but received %x\n", data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 idata);
169 return 1;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300170 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 return 0;
172}
173
174static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data)
175{
176 if (qcam_write_data(qcam, cmd))
177 return -1;
178 if (qcam_write_data(qcam, data))
179 return -1;
180 return 0;
181}
182
183static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd)
184{
185 if (qcam_write_data(qcam, cmd))
186 return -1;
187 return qcam_read_data(qcam);
188}
189
190static int qc_detect(struct qcam_device *qcam)
191{
192 unsigned int stat, ostat, i, count = 0;
193
194 /* The probe routine below is not very reliable. The IEEE-1284
195 probe takes precedence. */
196 /* XXX Currently parport provides no way to distinguish between
197 "the IEEE probe was not done" and "the probe was done, but
198 no device was found". Fix this one day. */
199 if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA
200 && qcam->pport->probe_info[0].model
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300201 && !strcmp(qcam->pdev->port->probe_info[0].model,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 "Color QuickCam 2.0")) {
203 printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
204 return 1;
205 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300206
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 if (probe < 2)
208 return 0;
209
210 parport_write_control(qcam->pport, 0xc);
211
212 /* look for a heartbeat */
213 ostat = stat = parport_read_status(qcam->pport);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300214 for (i=0; i<250; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 {
216 mdelay(1);
217 stat = parport_read_status(qcam->pport);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300218 if (ostat != stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 {
220 if (++count >= 3) return 1;
221 ostat = stat;
222 }
223 }
224
225 /* Reset the camera and try again */
226 parport_write_control(qcam->pport, 0xc);
227 parport_write_control(qcam->pport, 0x8);
228 mdelay(1);
229 parport_write_control(qcam->pport, 0xc);
230 mdelay(1);
231 count = 0;
232
233 ostat = stat = parport_read_status(qcam->pport);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300234 for (i=0; i<250; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 {
236 mdelay(1);
237 stat = parport_read_status(qcam->pport);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300238 if (ostat != stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 {
240 if (++count >= 3) return 1;
241 ostat = stat;
242 }
243 }
244
245 /* no (or flatline) camera, give up */
246 return 0;
247}
248
249static void qc_reset(struct qcam_device *qcam)
250{
251 parport_write_control(qcam->pport, 0xc);
252 parport_write_control(qcam->pport, 0x8);
253 mdelay(1);
254 parport_write_control(qcam->pport, 0xc);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300255 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256}
257
258/* Reset the QuickCam and program for brightness, contrast,
259 * white-balance, and resolution. */
260
261static void qc_setup(struct qcam_device *q)
262{
263 qc_reset(q);
264
265 /* Set the brightness. */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300266 qcam_set(q, 11, q->brightness);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268 /* Set the height and width. These refer to the actual
269 CCD area *before* applying the selected decimation. */
270 qcam_set(q, 17, q->ccd_height);
271 qcam_set(q, 19, q->ccd_width / 2);
272
273 /* Set top and left. */
274 qcam_set(q, 0xd, q->top);
275 qcam_set(q, 0xf, q->left);
276
277 /* Set contrast and white balance. */
278 qcam_set(q, 0x19, q->contrast);
279 qcam_set(q, 0x1f, q->whitebal);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 /* Set the speed. */
282 qcam_set(q, 45, 2);
283}
284
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300285/* Read some bytes from the camera and put them in the buffer.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 nbytes should be a multiple of 3, because bidirectional mode gives
287 us three bytes at a time. */
288
289static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes)
290{
291 unsigned int bytes = 0;
292
293 qcam_set_ack(q, 0);
294 if (q->bidirectional)
295 {
296 /* It's a bidirectional port */
297 while (bytes < nbytes)
298 {
299 unsigned int lo1, hi1, lo2, hi2;
300 unsigned char r, g, b;
301
302 if (qcam_await_ready2(q, 1)) return bytes;
303 lo1 = parport_read_data(q->pport) >> 1;
304 hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
305 qcam_set_ack(q, 1);
306 if (qcam_await_ready2(q, 0)) return bytes;
307 lo2 = parport_read_data(q->pport) >> 1;
308 hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
309 qcam_set_ack(q, 0);
310 r = (lo1 | ((hi1 & 1)<<7));
311 g = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1);
312 b = (lo2 | ((hi2 & 1)<<7));
313 if (force_rgb) {
314 buf[bytes++] = r;
315 buf[bytes++] = g;
316 buf[bytes++] = b;
317 } else {
318 buf[bytes++] = b;
319 buf[bytes++] = g;
320 buf[bytes++] = r;
321 }
322 }
323 }
324 else
325 {
326 /* It's a unidirectional port */
327 int i = 0, n = bytes;
328 unsigned char rgb[3];
329
330 while (bytes < nbytes)
331 {
332 unsigned int hi, lo;
333
334 if (qcam_await_ready1(q, 1)) return bytes;
335 hi = (parport_read_status(q->pport) & 0xf0);
336 qcam_set_ack(q, 1);
337 if (qcam_await_ready1(q, 0)) return bytes;
338 lo = (parport_read_status(q->pport) & 0xf0);
339 qcam_set_ack(q, 0);
340 /* flip some bits */
341 rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
342 if (i >= 2) {
343get_fragment:
344 if (force_rgb) {
345 buf[n++] = rgb[0];
346 buf[n++] = rgb[1];
347 buf[n++] = rgb[2];
348 } else {
349 buf[n++] = rgb[2];
350 buf[n++] = rgb[1];
351 buf[n++] = rgb[0];
352 }
353 }
354 }
355 if (i) {
356 i = 0;
357 goto get_fragment;
358 }
359 }
360 return bytes;
361}
362
363#define BUFSZ 150
364
365static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len)
366{
367 unsigned lines, pixelsperline, bitsperxfer;
368 unsigned int is_bi_dir = q->bidirectional;
369 size_t wantlen, outptr = 0;
370 char tmpbuf[BUFSZ];
371
372 if (!access_ok(VERIFY_WRITE, buf, len))
373 return -EFAULT;
374
375 /* Wait for camera to become ready */
376 for (;;)
377 {
378 int i = qcam_get(q, 41);
379 if (i == -1) {
380 qc_setup(q);
381 return -EIO;
382 }
383 if ((i & 0x80) == 0)
384 break;
385 else
386 schedule();
387 }
388
389 if (qcam_set(q, 7, (q->mode | (is_bi_dir?1:0)) + 1))
390 return -EIO;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300391
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 lines = q->height;
393 pixelsperline = q->width;
394 bitsperxfer = (is_bi_dir) ? 24 : 8;
395
396 if (is_bi_dir)
397 {
398 /* Turn the port around */
399 parport_data_reverse(q->pport);
400 mdelay(3);
401 qcam_set_ack(q, 0);
402 if (qcam_await_ready1(q, 1)) {
403 qc_setup(q);
404 return -EIO;
405 }
406 qcam_set_ack(q, 1);
407 if (qcam_await_ready1(q, 0)) {
408 qc_setup(q);
409 return -EIO;
410 }
411 }
412
413 wantlen = lines * pixelsperline * 24 / 8;
414
415 while (wantlen)
416 {
417 size_t t, s;
418 s = (wantlen > BUFSZ)?BUFSZ:wantlen;
419 t = qcam_read_bytes(q, tmpbuf, s);
420 if (outptr < len)
421 {
422 size_t sz = len - outptr;
423 if (sz > t) sz = t;
424 if (__copy_to_user(buf+outptr, tmpbuf, sz))
425 break;
426 outptr += sz;
427 }
428 wantlen -= t;
429 if (t < s)
430 break;
431 cond_resched();
432 }
433
434 len = outptr;
435
436 if (wantlen)
437 {
438 printk("qcam: short read.\n");
439 if (is_bi_dir)
440 parport_data_forward(q->pport);
441 qc_setup(q);
442 return len;
443 }
444
445 if (is_bi_dir)
446 {
447 int l;
448 do {
449 l = qcam_read_bytes(q, tmpbuf, 3);
450 cond_resched();
451 } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
452 if (force_rgb) {
453 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
454 printk("qcam: bad EOF\n");
455 } else {
456 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
457 printk("qcam: bad EOF\n");
458 }
459 qcam_set_ack(q, 0);
460 if (qcam_await_ready1(q, 1))
461 {
462 printk("qcam: no ack after EOF\n");
463 parport_data_forward(q->pport);
464 qc_setup(q);
465 return len;
466 }
467 parport_data_forward(q->pport);
468 mdelay(3);
469 qcam_set_ack(q, 1);
470 if (qcam_await_ready1(q, 0))
471 {
472 printk("qcam: no ack to port turnaround\n");
473 qc_setup(q);
474 return len;
475 }
476 }
477 else
478 {
479 int l;
480 do {
481 l = qcam_read_bytes(q, tmpbuf, 1);
482 cond_resched();
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
502static int qcam_do_ioctl(struct inode *inode, struct file *file,
503 unsigned int cmd, void *arg)
504{
505 struct video_device *dev = video_devdata(file);
506 struct qcam_device *qcam=(struct qcam_device *)dev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 switch(cmd)
509 {
510 case VIDIOCGCAP:
511 {
512 struct video_capability *b = arg;
513 strcpy(b->name, "Quickcam");
514 b->type = VID_TYPE_CAPTURE|VID_TYPE_SCALES;
515 b->channels = 1;
516 b->audios = 0;
517 b->maxwidth = 320;
518 b->maxheight = 240;
519 b->minwidth = 80;
520 b->minheight = 60;
521 return 0;
522 }
523 case VIDIOCGCHAN:
524 {
525 struct video_channel *v = arg;
526 if(v->channel!=0)
527 return -EINVAL;
528 v->flags=0;
529 v->tuners=0;
530 /* Good question.. its composite or SVHS so.. */
531 v->type = VIDEO_TYPE_CAMERA;
532 strcpy(v->name, "Camera");
533 return 0;
534 }
535 case VIDIOCSCHAN:
536 {
537 struct video_channel *v = arg;
538 if(v->channel!=0)
539 return -EINVAL;
540 return 0;
541 }
542 case VIDIOCGTUNER:
543 {
544 struct video_tuner *v = arg;
545 if(v->tuner)
546 return -EINVAL;
547 memset(v,0,sizeof(*v));
548 strcpy(v->name, "Format");
549 v->mode = VIDEO_MODE_AUTO;
550 return 0;
551 }
552 case VIDIOCSTUNER:
553 {
554 struct video_tuner *v = arg;
555 if(v->tuner)
556 return -EINVAL;
557 if(v->mode!=VIDEO_MODE_AUTO)
558 return -EINVAL;
559 return 0;
560 }
561 case VIDIOCGPICT:
562 {
563 struct video_picture *p = arg;
564 p->colour=0x8000;
565 p->hue=0x8000;
566 p->brightness=qcam->brightness<<8;
567 p->contrast=qcam->contrast<<8;
568 p->whiteness=qcam->whitebal<<8;
569 p->depth=24;
570 p->palette=VIDEO_PALETTE_RGB24;
571 return 0;
572 }
573 case VIDIOCSPICT:
574 {
575 struct video_picture *p = arg;
576
577 /*
578 * Sanity check args
579 */
580 if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24)
581 return -EINVAL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 /*
584 * Now load the camera.
585 */
586 qcam->brightness = p->brightness>>8;
587 qcam->contrast = p->contrast>>8;
588 qcam->whitebal = p->whiteness>>8;
589
Ingo Molnar3593cab2006-02-07 06:49:14 -0200590 mutex_lock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 parport_claim_or_block(qcam->pdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300592 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 parport_release(qcam->pdev);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200594 mutex_unlock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 return 0;
596 }
597 case VIDIOCSWIN:
598 {
599 struct video_window *vw = arg;
600
601 if(vw->flags)
602 return -EINVAL;
603 if(vw->clipcount)
604 return -EINVAL;
605 if(vw->height<60||vw->height>240)
606 return -EINVAL;
607 if(vw->width<80||vw->width>320)
608 return -EINVAL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 qcam->width = 80;
611 qcam->height = 60;
612 qcam->mode = QC_DECIMATION_4;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300613
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 if(vw->width>=160 && vw->height>=120)
615 {
616 qcam->width = 160;
617 qcam->height = 120;
618 qcam->mode = QC_DECIMATION_2;
619 }
620 if(vw->width>=320 && vw->height>=240)
621 {
622 qcam->width = 320;
623 qcam->height = 240;
624 qcam->mode = QC_DECIMATION_1;
625 }
626 qcam->mode |= QC_MILLIONS;
627#if 0
628 if(vw->width>=640 && vw->height>=480)
629 {
630 qcam->width = 640;
631 qcam->height = 480;
632 qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
633 }
634#endif
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300635 /* Ok we figured out what to use from our
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 wide choice */
Ingo Molnar3593cab2006-02-07 06:49:14 -0200637 mutex_lock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 parport_claim_or_block(qcam->pdev);
639 qc_setup(qcam);
640 parport_release(qcam->pdev);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200641 mutex_unlock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 return 0;
643 }
644 case VIDIOCGWIN:
645 {
646 struct video_window *vw = arg;
647 memset(vw, 0, sizeof(*vw));
648 vw->width=qcam->width;
649 vw->height=qcam->height;
650 return 0;
651 }
652 case VIDIOCKEY:
653 return 0;
654 case VIDIOCCAPTURE:
655 case VIDIOCGFBUF:
656 case VIDIOCSFBUF:
657 case VIDIOCGFREQ:
658 case VIDIOCSFREQ:
659 case VIDIOCGAUDIO:
660 case VIDIOCSAUDIO:
661 return -EINVAL;
662 default:
663 return -ENOIOCTLCMD;
664 }
665 return 0;
666}
667
668static int qcam_ioctl(struct inode *inode, struct file *file,
669 unsigned int cmd, unsigned long arg)
670{
671 return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl);
672}
673
674static ssize_t qcam_read(struct file *file, char __user *buf,
675 size_t count, loff_t *ppos)
676{
677 struct video_device *v = video_devdata(file);
678 struct qcam_device *qcam=(struct qcam_device *)v;
679 int len;
680
Ingo Molnar3593cab2006-02-07 06:49:14 -0200681 mutex_lock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 parport_claim_or_block(qcam->pdev);
683 /* Probably should have a semaphore against multiple users */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300684 len = qc_capture(qcam, buf,count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 parport_release(qcam->pdev);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200686 mutex_unlock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 return len;
688}
689
690/* video device template */
Arjan van de Venfa027c22007-02-12 00:55:33 -0800691static const struct file_operations qcam_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 .owner = THIS_MODULE,
693 .open = video_exclusive_open,
694 .release = video_exclusive_release,
695 .ioctl = qcam_ioctl,
Douglas Schilling Landgraf078ff792008-04-22 14:46:11 -0300696#ifdef CONFIG_COMPAT
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200697 .compat_ioctl = v4l_compat_ioctl32,
Douglas Schilling Landgraf078ff792008-04-22 14:46:11 -0300698#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 .read = qcam_read,
700 .llseek = no_llseek,
701};
702
703static struct video_device qcam_template=
704{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 .name = "Colour QuickCam",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 .fops = &qcam_fops,
707};
708
709/* Initialize the QuickCam driver control structure. */
710
711static struct qcam_device *qcam_init(struct parport *port)
712{
713 struct qcam_device *q;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
716 if(q==NULL)
717 return NULL;
718
719 q->pport = port;
720 q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
721 NULL, 0, NULL);
722
723 q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0;
724
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300725 if (q->pdev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 {
727 printk(KERN_ERR "c-qcam: couldn't register for %s.\n",
728 port->name);
729 kfree(q);
730 return NULL;
731 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
734
Ingo Molnar3593cab2006-02-07 06:49:14 -0200735 mutex_init(&q->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 q->width = q->ccd_width = 320;
737 q->height = q->ccd_height = 240;
738 q->mode = QC_MILLIONS | QC_DECIMATION_1;
739 q->contrast = 192;
740 q->brightness = 240;
741 q->whitebal = 128;
742 q->top = 1;
743 q->left = 14;
744 return q;
745}
746
747static struct qcam_device *qcams[MAX_CAMS];
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300748static unsigned int num_cams;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
750static int init_cqcam(struct parport *port)
751{
752 struct qcam_device *qcam;
753
754 if (parport[0] != -1)
755 {
756 /* The user gave specific instructions */
757 int i, found = 0;
758 for (i = 0; i < MAX_CAMS && parport[i] != -1; i++)
759 {
760 if (parport[0] == port->number)
761 found = 1;
762 }
763 if (!found)
764 return -ENODEV;
765 }
766
767 if (num_cams == MAX_CAMS)
768 return -ENOSPC;
769
770 qcam = qcam_init(port);
771 if (qcam==NULL)
772 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 parport_claim_or_block(qcam->pdev);
775
776 qc_reset(qcam);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300777
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 if (probe && qc_detect(qcam)==0)
779 {
780 parport_release(qcam->pdev);
781 parport_unregister_device(qcam->pdev);
782 kfree(qcam);
783 return -ENODEV;
784 }
785
786 qc_setup(qcam);
787
788 parport_release(qcam->pdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300789
Hans Verkuildc60de32008-09-03 17:11:58 -0300790 if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
792 qcam->pport->name);
793 parport_unregister_device(qcam->pdev);
794 kfree(qcam);
795 return -ENODEV;
796 }
797
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300798 printk(KERN_INFO "video%d: Colour QuickCam found on %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 qcam->vdev.minor, qcam->pport->name);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300800
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 qcams[num_cams++] = qcam;
802
803 return 0;
804}
805
806static void close_cqcam(struct qcam_device *qcam)
807{
808 video_unregister_device(&qcam->vdev);
809 parport_unregister_device(qcam->pdev);
810 kfree(qcam);
811}
812
813static void cq_attach(struct parport *port)
814{
815 init_cqcam(port);
816}
817
818static void cq_detach(struct parport *port)
819{
820 /* Write this some day. */
821}
822
823static struct parport_driver cqcam_driver = {
824 .name = "cqcam",
825 .attach = cq_attach,
826 .detach = cq_detach,
827};
828
829static int __init cqcam_init (void)
830{
831 printk(BANNER "\n");
832
833 return parport_register_driver(&cqcam_driver);
834}
835
836static void __exit cqcam_cleanup (void)
837{
838 unsigned int i;
839
840 for (i = 0; i < num_cams; i++)
841 close_cqcam(qcams[i]);
842
843 parport_unregister_driver(&cqcam_driver);
844}
845
846MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
847MODULE_DESCRIPTION(BANNER);
848MODULE_LICENSE("GPL");
849
850/* FIXME: parport=auto would never have worked, surely? --RR */
851MODULE_PARM_DESC(parport ,"parport=<auto|n[,n]...> for port detection method\n\
852probe=<0|1|2> for camera detection method\n\
853force_rgb=<0|1> for RGB data format (default BGR)");
854module_param_array(parport, int, NULL, 0);
855module_param(probe, int, 0);
856module_param(force_rgb, bool, 0);
857module_param(video_nr, int, 0);
858
859module_init(cqcam_init);
860module_exit(cqcam_cleanup);