blob: 0f930d35146619fea78c43a0370b6fec6fdaba0f [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;
Hans Verkuil7d43cd52008-08-23 05:31:47 -030054 unsigned long in_use;
Ingo Molnar3593cab2006-02-07 06:49:14 -020055 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056};
57
58/* cameras maximum */
59#define MAX_CAMS 4
60
61/* The three possible QuickCam modes */
62#define QC_MILLIONS 0x18
63#define QC_BILLIONS 0x10
64#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */
65
66/* The three possible decimations */
67#define QC_DECIMATION_1 0
68#define QC_DECIMATION_2 2
69#define QC_DECIMATION_4 4
70
71#define BANNER "Colour QuickCam for Video4Linux v0.05"
72
73static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
74static int probe = 2;
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030075static int force_rgb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static int video_nr = -1;
77
78static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
79{
80 /* note: the QC specs refer to the PCAck pin by voltage, not
81 software level. PC ports have builtin inverters. */
82 parport_frob_control(qcam->pport, 8, i?8:0);
83}
84
85static inline unsigned int qcam_ready1(struct qcam_device *qcam)
86{
87 return (parport_read_status(qcam->pport) & 0x8)?1:0;
88}
89
90static inline unsigned int qcam_ready2(struct qcam_device *qcam)
91{
92 return (parport_read_data(qcam->pport) & 0x1)?1:0;
93}
94
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030095static unsigned int qcam_await_ready1(struct qcam_device *qcam,
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 int value)
97{
98 unsigned long oldjiffies = jiffies;
99 unsigned int i;
100
Julia Lawall168c6262008-04-16 16:13:15 -0300101 for (oldjiffies = jiffies;
102 time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 if (qcam_ready1(qcam) == value)
104 return 0;
105
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300106 /* If the camera didn't respond within 1/25 second, poll slowly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 for a while. */
108 for (i = 0; i < 50; i++)
109 {
110 if (qcam_ready1(qcam) == value)
111 return 0;
112 msleep_interruptible(100);
113 }
114
115 /* Probably somebody pulled the plug out. Not much we can do. */
116 printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value,
117 parport_read_status(qcam->pport),
118 parport_read_control(qcam->pport));
119 return 1;
120}
121
122static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
123{
124 unsigned long oldjiffies = jiffies;
125 unsigned int i;
126
Julia Lawall168c6262008-04-16 16:13:15 -0300127 for (oldjiffies = jiffies;
128 time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 if (qcam_ready2(qcam) == value)
130 return 0;
131
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300132 /* If the camera didn't respond within 1/25 second, poll slowly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 for a while. */
134 for (i = 0; i < 50; i++)
135 {
136 if (qcam_ready2(qcam) == value)
137 return 0;
138 msleep_interruptible(100);
139 }
140
141 /* Probably somebody pulled the plug out. Not much we can do. */
142 printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value,
143 parport_read_status(qcam->pport),
144 parport_read_control(qcam->pport),
145 parport_read_data(qcam->pport));
146 return 1;
147}
148
149static int qcam_read_data(struct qcam_device *qcam)
150{
151 unsigned int idata;
152 qcam_set_ack(qcam, 0);
153 if (qcam_await_ready1(qcam, 1)) return -1;
154 idata = parport_read_status(qcam->pport) & 0xf0;
155 qcam_set_ack(qcam, 1);
156 if (qcam_await_ready1(qcam, 0)) return -1;
157 idata |= (parport_read_status(qcam->pport) >> 4);
158 return idata;
159}
160
161static int qcam_write_data(struct qcam_device *qcam, unsigned int data)
162{
163 unsigned int idata;
164 parport_write_data(qcam->pport, data);
165 idata = qcam_read_data(qcam);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300166 if (data != idata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 {
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300168 printk(KERN_WARNING "cqcam: sent %x but received %x\n", data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 idata);
170 return 1;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 return 0;
173}
174
175static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data)
176{
177 if (qcam_write_data(qcam, cmd))
178 return -1;
179 if (qcam_write_data(qcam, data))
180 return -1;
181 return 0;
182}
183
184static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd)
185{
186 if (qcam_write_data(qcam, cmd))
187 return -1;
188 return qcam_read_data(qcam);
189}
190
191static int qc_detect(struct qcam_device *qcam)
192{
193 unsigned int stat, ostat, i, count = 0;
194
195 /* The probe routine below is not very reliable. The IEEE-1284
196 probe takes precedence. */
197 /* XXX Currently parport provides no way to distinguish between
198 "the IEEE probe was not done" and "the probe was done, but
199 no device was found". Fix this one day. */
200 if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA
201 && qcam->pport->probe_info[0].model
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300202 && !strcmp(qcam->pdev->port->probe_info[0].model,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 "Color QuickCam 2.0")) {
204 printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
205 return 1;
206 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300207
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 if (probe < 2)
209 return 0;
210
211 parport_write_control(qcam->pport, 0xc);
212
213 /* look for a heartbeat */
214 ostat = stat = parport_read_status(qcam->pport);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300215 for (i=0; i<250; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 {
217 mdelay(1);
218 stat = parport_read_status(qcam->pport);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300219 if (ostat != stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 {
221 if (++count >= 3) return 1;
222 ostat = stat;
223 }
224 }
225
226 /* Reset the camera and try again */
227 parport_write_control(qcam->pport, 0xc);
228 parport_write_control(qcam->pport, 0x8);
229 mdelay(1);
230 parport_write_control(qcam->pport, 0xc);
231 mdelay(1);
232 count = 0;
233
234 ostat = stat = parport_read_status(qcam->pport);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300235 for (i=0; i<250; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 {
237 mdelay(1);
238 stat = parport_read_status(qcam->pport);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300239 if (ostat != stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 {
241 if (++count >= 3) return 1;
242 ostat = stat;
243 }
244 }
245
246 /* no (or flatline) camera, give up */
247 return 0;
248}
249
250static void qc_reset(struct qcam_device *qcam)
251{
252 parport_write_control(qcam->pport, 0xc);
253 parport_write_control(qcam->pport, 0x8);
254 mdelay(1);
255 parport_write_control(qcam->pport, 0xc);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300256 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257}
258
259/* Reset the QuickCam and program for brightness, contrast,
260 * white-balance, and resolution. */
261
262static void qc_setup(struct qcam_device *q)
263{
264 qc_reset(q);
265
266 /* Set the brightness. */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300267 qcam_set(q, 11, q->brightness);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
269 /* Set the height and width. These refer to the actual
270 CCD area *before* applying the selected decimation. */
271 qcam_set(q, 17, q->ccd_height);
272 qcam_set(q, 19, q->ccd_width / 2);
273
274 /* Set top and left. */
275 qcam_set(q, 0xd, q->top);
276 qcam_set(q, 0xf, q->left);
277
278 /* Set contrast and white balance. */
279 qcam_set(q, 0x19, q->contrast);
280 qcam_set(q, 0x1f, q->whitebal);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 /* Set the speed. */
283 qcam_set(q, 45, 2);
284}
285
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300286/* Read some bytes from the camera and put them in the buffer.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 nbytes should be a multiple of 3, because bidirectional mode gives
288 us three bytes at a time. */
289
290static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes)
291{
292 unsigned int bytes = 0;
293
294 qcam_set_ack(q, 0);
295 if (q->bidirectional)
296 {
297 /* It's a bidirectional port */
298 while (bytes < nbytes)
299 {
300 unsigned int lo1, hi1, lo2, hi2;
301 unsigned char r, g, b;
302
303 if (qcam_await_ready2(q, 1)) return bytes;
304 lo1 = parport_read_data(q->pport) >> 1;
305 hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
306 qcam_set_ack(q, 1);
307 if (qcam_await_ready2(q, 0)) return bytes;
308 lo2 = parport_read_data(q->pport) >> 1;
309 hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
310 qcam_set_ack(q, 0);
311 r = (lo1 | ((hi1 & 1)<<7));
312 g = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1);
313 b = (lo2 | ((hi2 & 1)<<7));
314 if (force_rgb) {
315 buf[bytes++] = r;
316 buf[bytes++] = g;
317 buf[bytes++] = b;
318 } else {
319 buf[bytes++] = b;
320 buf[bytes++] = g;
321 buf[bytes++] = r;
322 }
323 }
324 }
325 else
326 {
327 /* It's a unidirectional port */
328 int i = 0, n = bytes;
329 unsigned char rgb[3];
330
331 while (bytes < nbytes)
332 {
333 unsigned int hi, lo;
334
335 if (qcam_await_ready1(q, 1)) return bytes;
336 hi = (parport_read_status(q->pport) & 0xf0);
337 qcam_set_ack(q, 1);
338 if (qcam_await_ready1(q, 0)) return bytes;
339 lo = (parport_read_status(q->pport) & 0xf0);
340 qcam_set_ack(q, 0);
341 /* flip some bits */
342 rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
343 if (i >= 2) {
344get_fragment:
345 if (force_rgb) {
346 buf[n++] = rgb[0];
347 buf[n++] = rgb[1];
348 buf[n++] = rgb[2];
349 } else {
350 buf[n++] = rgb[2];
351 buf[n++] = rgb[1];
352 buf[n++] = rgb[0];
353 }
354 }
355 }
356 if (i) {
357 i = 0;
358 goto get_fragment;
359 }
360 }
361 return bytes;
362}
363
364#define BUFSZ 150
365
366static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len)
367{
368 unsigned lines, pixelsperline, bitsperxfer;
369 unsigned int is_bi_dir = q->bidirectional;
370 size_t wantlen, outptr = 0;
371 char tmpbuf[BUFSZ];
372
373 if (!access_ok(VERIFY_WRITE, buf, len))
374 return -EFAULT;
375
376 /* Wait for camera to become ready */
377 for (;;)
378 {
379 int i = qcam_get(q, 41);
380 if (i == -1) {
381 qc_setup(q);
382 return -EIO;
383 }
384 if ((i & 0x80) == 0)
385 break;
386 else
387 schedule();
388 }
389
390 if (qcam_set(q, 7, (q->mode | (is_bi_dir?1:0)) + 1))
391 return -EIO;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300392
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 lines = q->height;
394 pixelsperline = q->width;
395 bitsperxfer = (is_bi_dir) ? 24 : 8;
396
397 if (is_bi_dir)
398 {
399 /* Turn the port around */
400 parport_data_reverse(q->pport);
401 mdelay(3);
402 qcam_set_ack(q, 0);
403 if (qcam_await_ready1(q, 1)) {
404 qc_setup(q);
405 return -EIO;
406 }
407 qcam_set_ack(q, 1);
408 if (qcam_await_ready1(q, 0)) {
409 qc_setup(q);
410 return -EIO;
411 }
412 }
413
414 wantlen = lines * pixelsperline * 24 / 8;
415
416 while (wantlen)
417 {
418 size_t t, s;
419 s = (wantlen > BUFSZ)?BUFSZ:wantlen;
420 t = qcam_read_bytes(q, tmpbuf, s);
421 if (outptr < len)
422 {
423 size_t sz = len - outptr;
424 if (sz > t) sz = t;
425 if (__copy_to_user(buf+outptr, tmpbuf, sz))
426 break;
427 outptr += sz;
428 }
429 wantlen -= t;
430 if (t < s)
431 break;
432 cond_resched();
433 }
434
435 len = outptr;
436
437 if (wantlen)
438 {
439 printk("qcam: short read.\n");
440 if (is_bi_dir)
441 parport_data_forward(q->pport);
442 qc_setup(q);
443 return len;
444 }
445
446 if (is_bi_dir)
447 {
448 int l;
449 do {
450 l = qcam_read_bytes(q, tmpbuf, 3);
451 cond_resched();
452 } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
453 if (force_rgb) {
454 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
455 printk("qcam: bad EOF\n");
456 } else {
457 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
458 printk("qcam: bad EOF\n");
459 }
460 qcam_set_ack(q, 0);
461 if (qcam_await_ready1(q, 1))
462 {
463 printk("qcam: no ack after EOF\n");
464 parport_data_forward(q->pport);
465 qc_setup(q);
466 return len;
467 }
468 parport_data_forward(q->pport);
469 mdelay(3);
470 qcam_set_ack(q, 1);
471 if (qcam_await_ready1(q, 0))
472 {
473 printk("qcam: no ack to port turnaround\n");
474 qc_setup(q);
475 return len;
476 }
477 }
478 else
479 {
480 int l;
481 do {
482 l = qcam_read_bytes(q, tmpbuf, 1);
483 cond_resched();
484 } while (l && tmpbuf[0] == 0x7e);
485 l = qcam_read_bytes(q, tmpbuf+1, 2);
486 if (force_rgb) {
487 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
488 printk("qcam: bad EOF\n");
489 } else {
490 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
491 printk("qcam: bad EOF\n");
492 }
493 }
494
495 qcam_write_data(q, 0);
496 return len;
497}
498
499/*
500 * Video4linux interfacing
501 */
502
503static int qcam_do_ioctl(struct inode *inode, struct file *file,
504 unsigned int cmd, void *arg)
505{
506 struct video_device *dev = video_devdata(file);
507 struct qcam_device *qcam=(struct qcam_device *)dev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300508
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 switch(cmd)
510 {
511 case VIDIOCGCAP:
512 {
513 struct video_capability *b = arg;
514 strcpy(b->name, "Quickcam");
515 b->type = VID_TYPE_CAPTURE|VID_TYPE_SCALES;
516 b->channels = 1;
517 b->audios = 0;
518 b->maxwidth = 320;
519 b->maxheight = 240;
520 b->minwidth = 80;
521 b->minheight = 60;
522 return 0;
523 }
524 case VIDIOCGCHAN:
525 {
526 struct video_channel *v = arg;
527 if(v->channel!=0)
528 return -EINVAL;
529 v->flags=0;
530 v->tuners=0;
531 /* Good question.. its composite or SVHS so.. */
532 v->type = VIDEO_TYPE_CAMERA;
533 strcpy(v->name, "Camera");
534 return 0;
535 }
536 case VIDIOCSCHAN:
537 {
538 struct video_channel *v = arg;
539 if(v->channel!=0)
540 return -EINVAL;
541 return 0;
542 }
543 case VIDIOCGTUNER:
544 {
545 struct video_tuner *v = arg;
546 if(v->tuner)
547 return -EINVAL;
548 memset(v,0,sizeof(*v));
549 strcpy(v->name, "Format");
550 v->mode = VIDEO_MODE_AUTO;
551 return 0;
552 }
553 case VIDIOCSTUNER:
554 {
555 struct video_tuner *v = arg;
556 if(v->tuner)
557 return -EINVAL;
558 if(v->mode!=VIDEO_MODE_AUTO)
559 return -EINVAL;
560 return 0;
561 }
562 case VIDIOCGPICT:
563 {
564 struct video_picture *p = arg;
565 p->colour=0x8000;
566 p->hue=0x8000;
567 p->brightness=qcam->brightness<<8;
568 p->contrast=qcam->contrast<<8;
569 p->whiteness=qcam->whitebal<<8;
570 p->depth=24;
571 p->palette=VIDEO_PALETTE_RGB24;
572 return 0;
573 }
574 case VIDIOCSPICT:
575 {
576 struct video_picture *p = arg;
577
578 /*
579 * Sanity check args
580 */
581 if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24)
582 return -EINVAL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 /*
585 * Now load the camera.
586 */
587 qcam->brightness = p->brightness>>8;
588 qcam->contrast = p->contrast>>8;
589 qcam->whitebal = p->whiteness>>8;
590
Ingo Molnar3593cab2006-02-07 06:49:14 -0200591 mutex_lock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 parport_claim_or_block(qcam->pdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300593 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 parport_release(qcam->pdev);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200595 mutex_unlock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 return 0;
597 }
598 case VIDIOCSWIN:
599 {
600 struct video_window *vw = arg;
601
602 if(vw->flags)
603 return -EINVAL;
604 if(vw->clipcount)
605 return -EINVAL;
606 if(vw->height<60||vw->height>240)
607 return -EINVAL;
608 if(vw->width<80||vw->width>320)
609 return -EINVAL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 qcam->width = 80;
612 qcam->height = 60;
613 qcam->mode = QC_DECIMATION_4;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300614
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 if(vw->width>=160 && vw->height>=120)
616 {
617 qcam->width = 160;
618 qcam->height = 120;
619 qcam->mode = QC_DECIMATION_2;
620 }
621 if(vw->width>=320 && vw->height>=240)
622 {
623 qcam->width = 320;
624 qcam->height = 240;
625 qcam->mode = QC_DECIMATION_1;
626 }
627 qcam->mode |= QC_MILLIONS;
628#if 0
629 if(vw->width>=640 && vw->height>=480)
630 {
631 qcam->width = 640;
632 qcam->height = 480;
633 qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
634 }
635#endif
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300636 /* Ok we figured out what to use from our
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 wide choice */
Ingo Molnar3593cab2006-02-07 06:49:14 -0200638 mutex_lock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 parport_claim_or_block(qcam->pdev);
640 qc_setup(qcam);
641 parport_release(qcam->pdev);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200642 mutex_unlock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 return 0;
644 }
645 case VIDIOCGWIN:
646 {
647 struct video_window *vw = arg;
648 memset(vw, 0, sizeof(*vw));
649 vw->width=qcam->width;
650 vw->height=qcam->height;
651 return 0;
652 }
653 case VIDIOCKEY:
654 return 0;
655 case VIDIOCCAPTURE:
656 case VIDIOCGFBUF:
657 case VIDIOCSFBUF:
658 case VIDIOCGFREQ:
659 case VIDIOCSFREQ:
660 case VIDIOCGAUDIO:
661 case VIDIOCSAUDIO:
662 return -EINVAL;
663 default:
664 return -ENOIOCTLCMD;
665 }
666 return 0;
667}
668
669static int qcam_ioctl(struct inode *inode, struct file *file,
670 unsigned int cmd, unsigned long arg)
671{
672 return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl);
673}
674
675static ssize_t qcam_read(struct file *file, char __user *buf,
676 size_t count, loff_t *ppos)
677{
678 struct video_device *v = video_devdata(file);
679 struct qcam_device *qcam=(struct qcam_device *)v;
680 int len;
681
Ingo Molnar3593cab2006-02-07 06:49:14 -0200682 mutex_lock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 parport_claim_or_block(qcam->pdev);
684 /* Probably should have a semaphore against multiple users */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300685 len = qc_capture(qcam, buf,count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 parport_release(qcam->pdev);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200687 mutex_unlock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 return len;
689}
690
Hans Verkuil7d43cd52008-08-23 05:31:47 -0300691static int qcam_exclusive_open(struct inode *inode, struct file *file)
692{
693 struct video_device *dev = video_devdata(file);
694 struct qcam_device *qcam = (struct qcam_device *)dev;
695
696 return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
697}
698
699static int qcam_exclusive_release(struct inode *inode, struct file *file)
700{
701 struct video_device *dev = video_devdata(file);
702 struct qcam_device *qcam = (struct qcam_device *)dev;
703
704 clear_bit(0, &qcam->in_use);
705 return 0;
706}
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708/* video device template */
Arjan van de Venfa027c22007-02-12 00:55:33 -0800709static const struct file_operations qcam_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 .owner = THIS_MODULE,
Hans Verkuil7d43cd52008-08-23 05:31:47 -0300711 .open = qcam_exclusive_open,
712 .release = qcam_exclusive_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 .ioctl = qcam_ioctl,
Douglas Schilling Landgraf078ff792008-04-22 14:46:11 -0300714#ifdef CONFIG_COMPAT
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200715 .compat_ioctl = v4l_compat_ioctl32,
Douglas Schilling Landgraf078ff792008-04-22 14:46:11 -0300716#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 .read = qcam_read,
718 .llseek = no_llseek,
719};
720
721static struct video_device qcam_template=
722{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 .name = "Colour QuickCam",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 .fops = &qcam_fops,
Hans Verkuilaa5e90a2008-08-23 06:23:55 -0300725 .release = video_device_release_empty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726};
727
728/* Initialize the QuickCam driver control structure. */
729
730static struct qcam_device *qcam_init(struct parport *port)
731{
732 struct qcam_device *q;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
735 if(q==NULL)
736 return NULL;
737
738 q->pport = port;
739 q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
740 NULL, 0, NULL);
741
742 q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0;
743
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300744 if (q->pdev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 {
746 printk(KERN_ERR "c-qcam: couldn't register for %s.\n",
747 port->name);
748 kfree(q);
749 return NULL;
750 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
753
Ingo Molnar3593cab2006-02-07 06:49:14 -0200754 mutex_init(&q->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 q->width = q->ccd_width = 320;
756 q->height = q->ccd_height = 240;
757 q->mode = QC_MILLIONS | QC_DECIMATION_1;
758 q->contrast = 192;
759 q->brightness = 240;
760 q->whitebal = 128;
761 q->top = 1;
762 q->left = 14;
763 return q;
764}
765
766static struct qcam_device *qcams[MAX_CAMS];
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300767static unsigned int num_cams;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
769static int init_cqcam(struct parport *port)
770{
771 struct qcam_device *qcam;
772
773 if (parport[0] != -1)
774 {
775 /* The user gave specific instructions */
776 int i, found = 0;
777 for (i = 0; i < MAX_CAMS && parport[i] != -1; i++)
778 {
779 if (parport[0] == port->number)
780 found = 1;
781 }
782 if (!found)
783 return -ENODEV;
784 }
785
786 if (num_cams == MAX_CAMS)
787 return -ENOSPC;
788
789 qcam = qcam_init(port);
790 if (qcam==NULL)
791 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300792
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 parport_claim_or_block(qcam->pdev);
794
795 qc_reset(qcam);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300796
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 if (probe && qc_detect(qcam)==0)
798 {
799 parport_release(qcam->pdev);
800 parport_unregister_device(qcam->pdev);
801 kfree(qcam);
802 return -ENODEV;
803 }
804
805 qc_setup(qcam);
806
807 parport_release(qcam->pdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300808
Hans Verkuildc60de32008-09-03 17:11:58 -0300809 if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
811 qcam->pport->name);
812 parport_unregister_device(qcam->pdev);
813 kfree(qcam);
814 return -ENODEV;
815 }
816
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300817 printk(KERN_INFO "video%d: Colour QuickCam found on %s\n",
Hans Verkuilc6330fb2008-10-19 18:54:26 -0300818 qcam->vdev.num, qcam->pport->name);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300819
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 qcams[num_cams++] = qcam;
821
822 return 0;
823}
824
825static void close_cqcam(struct qcam_device *qcam)
826{
827 video_unregister_device(&qcam->vdev);
828 parport_unregister_device(qcam->pdev);
829 kfree(qcam);
830}
831
832static void cq_attach(struct parport *port)
833{
834 init_cqcam(port);
835}
836
837static void cq_detach(struct parport *port)
838{
839 /* Write this some day. */
840}
841
842static struct parport_driver cqcam_driver = {
843 .name = "cqcam",
844 .attach = cq_attach,
845 .detach = cq_detach,
846};
847
848static int __init cqcam_init (void)
849{
850 printk(BANNER "\n");
851
852 return parport_register_driver(&cqcam_driver);
853}
854
855static void __exit cqcam_cleanup (void)
856{
857 unsigned int i;
858
859 for (i = 0; i < num_cams; i++)
860 close_cqcam(qcams[i]);
861
862 parport_unregister_driver(&cqcam_driver);
863}
864
865MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
866MODULE_DESCRIPTION(BANNER);
867MODULE_LICENSE("GPL");
868
869/* FIXME: parport=auto would never have worked, surely? --RR */
870MODULE_PARM_DESC(parport ,"parport=<auto|n[,n]...> for port detection method\n\
871probe=<0|1|2> for camera detection method\n\
872force_rgb=<0|1> for RGB data format (default BGR)");
873module_param_array(parport, int, NULL, 0);
874module_param(probe, int, 0);
875module_param(force_rgb, bool, 0);
876module_param(video_nr, int, 0);
877
878module_init(cqcam_init);
879module_exit(cqcam_cleanup);