blob: fe1e67bb1ca860b6a946afb0ed6804654c8bf4ce [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>
Ingo Molnar3593cab2006-02-07 06:49:14 -020038#include <linux/mutex.h>
Julia Lawall168c6262008-04-16 16:13:15 -030039#include <linux/jiffies.h>
Ingo Molnar3593cab2006-02-07 06:49:14 -020040
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <asm/uaccess.h>
42
43struct qcam_device {
44 struct video_device vdev;
45 struct pardevice *pdev;
46 struct parport *pport;
47 int width, height;
48 int ccd_width, ccd_height;
49 int mode;
50 int contrast, brightness, whitebal;
51 int top, left;
52 unsigned int bidirectional;
Ingo Molnar3593cab2006-02-07 06:49:14 -020053 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054};
55
56/* cameras maximum */
57#define MAX_CAMS 4
58
59/* The three possible QuickCam modes */
60#define QC_MILLIONS 0x18
61#define QC_BILLIONS 0x10
62#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */
63
64/* The three possible decimations */
65#define QC_DECIMATION_1 0
66#define QC_DECIMATION_2 2
67#define QC_DECIMATION_4 4
68
69#define BANNER "Colour QuickCam for Video4Linux v0.05"
70
71static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
72static int probe = 2;
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030073static int force_rgb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074static int video_nr = -1;
75
76static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
77{
78 /* note: the QC specs refer to the PCAck pin by voltage, not
79 software level. PC ports have builtin inverters. */
80 parport_frob_control(qcam->pport, 8, i?8:0);
81}
82
83static inline unsigned int qcam_ready1(struct qcam_device *qcam)
84{
85 return (parport_read_status(qcam->pport) & 0x8)?1:0;
86}
87
88static inline unsigned int qcam_ready2(struct qcam_device *qcam)
89{
90 return (parport_read_data(qcam->pport) & 0x1)?1:0;
91}
92
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030093static unsigned int qcam_await_ready1(struct qcam_device *qcam,
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 int value)
95{
96 unsigned long oldjiffies = jiffies;
97 unsigned int i;
98
Julia Lawall168c6262008-04-16 16:13:15 -030099 for (oldjiffies = jiffies;
100 time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 if (qcam_ready1(qcam) == value)
102 return 0;
103
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300104 /* If the camera didn't respond within 1/25 second, poll slowly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 for a while. */
106 for (i = 0; i < 50; i++)
107 {
108 if (qcam_ready1(qcam) == value)
109 return 0;
110 msleep_interruptible(100);
111 }
112
113 /* Probably somebody pulled the plug out. Not much we can do. */
114 printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value,
115 parport_read_status(qcam->pport),
116 parport_read_control(qcam->pport));
117 return 1;
118}
119
120static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
121{
122 unsigned long oldjiffies = jiffies;
123 unsigned int i;
124
Julia Lawall168c6262008-04-16 16:13:15 -0300125 for (oldjiffies = jiffies;
126 time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 if (qcam_ready2(qcam) == value)
128 return 0;
129
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300130 /* If the camera didn't respond within 1/25 second, poll slowly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 for a while. */
132 for (i = 0; i < 50; i++)
133 {
134 if (qcam_ready2(qcam) == value)
135 return 0;
136 msleep_interruptible(100);
137 }
138
139 /* Probably somebody pulled the plug out. Not much we can do. */
140 printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value,
141 parport_read_status(qcam->pport),
142 parport_read_control(qcam->pport),
143 parport_read_data(qcam->pport));
144 return 1;
145}
146
147static int qcam_read_data(struct qcam_device *qcam)
148{
149 unsigned int idata;
150 qcam_set_ack(qcam, 0);
151 if (qcam_await_ready1(qcam, 1)) return -1;
152 idata = parport_read_status(qcam->pport) & 0xf0;
153 qcam_set_ack(qcam, 1);
154 if (qcam_await_ready1(qcam, 0)) return -1;
155 idata |= (parport_read_status(qcam->pport) >> 4);
156 return idata;
157}
158
159static int qcam_write_data(struct qcam_device *qcam, unsigned int data)
160{
161 unsigned int idata;
162 parport_write_data(qcam->pport, data);
163 idata = qcam_read_data(qcam);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300164 if (data != idata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 {
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300166 printk(KERN_WARNING "cqcam: sent %x but received %x\n", data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 idata);
168 return 1;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 return 0;
171}
172
173static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data)
174{
175 if (qcam_write_data(qcam, cmd))
176 return -1;
177 if (qcam_write_data(qcam, data))
178 return -1;
179 return 0;
180}
181
182static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd)
183{
184 if (qcam_write_data(qcam, cmd))
185 return -1;
186 return qcam_read_data(qcam);
187}
188
189static int qc_detect(struct qcam_device *qcam)
190{
191 unsigned int stat, ostat, i, count = 0;
192
193 /* The probe routine below is not very reliable. The IEEE-1284
194 probe takes precedence. */
195 /* XXX Currently parport provides no way to distinguish between
196 "the IEEE probe was not done" and "the probe was done, but
197 no device was found". Fix this one day. */
198 if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA
199 && qcam->pport->probe_info[0].model
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300200 && !strcmp(qcam->pdev->port->probe_info[0].model,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 "Color QuickCam 2.0")) {
202 printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
203 return 1;
204 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300205
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 if (probe < 2)
207 return 0;
208
209 parport_write_control(qcam->pport, 0xc);
210
211 /* look for a heartbeat */
212 ostat = stat = parport_read_status(qcam->pport);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300213 for (i=0; i<250; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 {
215 mdelay(1);
216 stat = parport_read_status(qcam->pport);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300217 if (ostat != stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 {
219 if (++count >= 3) return 1;
220 ostat = stat;
221 }
222 }
223
224 /* Reset the camera and try again */
225 parport_write_control(qcam->pport, 0xc);
226 parport_write_control(qcam->pport, 0x8);
227 mdelay(1);
228 parport_write_control(qcam->pport, 0xc);
229 mdelay(1);
230 count = 0;
231
232 ostat = stat = parport_read_status(qcam->pport);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300233 for (i=0; i<250; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 {
235 mdelay(1);
236 stat = parport_read_status(qcam->pport);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300237 if (ostat != stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 {
239 if (++count >= 3) return 1;
240 ostat = stat;
241 }
242 }
243
244 /* no (or flatline) camera, give up */
245 return 0;
246}
247
248static void qc_reset(struct qcam_device *qcam)
249{
250 parport_write_control(qcam->pport, 0xc);
251 parport_write_control(qcam->pport, 0x8);
252 mdelay(1);
253 parport_write_control(qcam->pport, 0xc);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300254 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255}
256
257/* Reset the QuickCam and program for brightness, contrast,
258 * white-balance, and resolution. */
259
260static void qc_setup(struct qcam_device *q)
261{
262 qc_reset(q);
263
264 /* Set the brightness. */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300265 qcam_set(q, 11, q->brightness);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267 /* Set the height and width. These refer to the actual
268 CCD area *before* applying the selected decimation. */
269 qcam_set(q, 17, q->ccd_height);
270 qcam_set(q, 19, q->ccd_width / 2);
271
272 /* Set top and left. */
273 qcam_set(q, 0xd, q->top);
274 qcam_set(q, 0xf, q->left);
275
276 /* Set contrast and white balance. */
277 qcam_set(q, 0x19, q->contrast);
278 qcam_set(q, 0x1f, q->whitebal);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300279
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 /* Set the speed. */
281 qcam_set(q, 45, 2);
282}
283
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300284/* Read some bytes from the camera and put them in the buffer.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 nbytes should be a multiple of 3, because bidirectional mode gives
286 us three bytes at a time. */
287
288static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes)
289{
290 unsigned int bytes = 0;
291
292 qcam_set_ack(q, 0);
293 if (q->bidirectional)
294 {
295 /* It's a bidirectional port */
296 while (bytes < nbytes)
297 {
298 unsigned int lo1, hi1, lo2, hi2;
299 unsigned char r, g, b;
300
301 if (qcam_await_ready2(q, 1)) return bytes;
302 lo1 = parport_read_data(q->pport) >> 1;
303 hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
304 qcam_set_ack(q, 1);
305 if (qcam_await_ready2(q, 0)) return bytes;
306 lo2 = parport_read_data(q->pport) >> 1;
307 hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
308 qcam_set_ack(q, 0);
309 r = (lo1 | ((hi1 & 1)<<7));
310 g = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1);
311 b = (lo2 | ((hi2 & 1)<<7));
312 if (force_rgb) {
313 buf[bytes++] = r;
314 buf[bytes++] = g;
315 buf[bytes++] = b;
316 } else {
317 buf[bytes++] = b;
318 buf[bytes++] = g;
319 buf[bytes++] = r;
320 }
321 }
322 }
323 else
324 {
325 /* It's a unidirectional port */
326 int i = 0, n = bytes;
327 unsigned char rgb[3];
328
329 while (bytes < nbytes)
330 {
331 unsigned int hi, lo;
332
333 if (qcam_await_ready1(q, 1)) return bytes;
334 hi = (parport_read_status(q->pport) & 0xf0);
335 qcam_set_ack(q, 1);
336 if (qcam_await_ready1(q, 0)) return bytes;
337 lo = (parport_read_status(q->pport) & 0xf0);
338 qcam_set_ack(q, 0);
339 /* flip some bits */
340 rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
341 if (i >= 2) {
342get_fragment:
343 if (force_rgb) {
344 buf[n++] = rgb[0];
345 buf[n++] = rgb[1];
346 buf[n++] = rgb[2];
347 } else {
348 buf[n++] = rgb[2];
349 buf[n++] = rgb[1];
350 buf[n++] = rgb[0];
351 }
352 }
353 }
354 if (i) {
355 i = 0;
356 goto get_fragment;
357 }
358 }
359 return bytes;
360}
361
362#define BUFSZ 150
363
364static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len)
365{
366 unsigned lines, pixelsperline, bitsperxfer;
367 unsigned int is_bi_dir = q->bidirectional;
368 size_t wantlen, outptr = 0;
369 char tmpbuf[BUFSZ];
370
371 if (!access_ok(VERIFY_WRITE, buf, len))
372 return -EFAULT;
373
374 /* Wait for camera to become ready */
375 for (;;)
376 {
377 int i = qcam_get(q, 41);
378 if (i == -1) {
379 qc_setup(q);
380 return -EIO;
381 }
382 if ((i & 0x80) == 0)
383 break;
384 else
385 schedule();
386 }
387
388 if (qcam_set(q, 7, (q->mode | (is_bi_dir?1:0)) + 1))
389 return -EIO;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 lines = q->height;
392 pixelsperline = q->width;
393 bitsperxfer = (is_bi_dir) ? 24 : 8;
394
395 if (is_bi_dir)
396 {
397 /* Turn the port around */
398 parport_data_reverse(q->pport);
399 mdelay(3);
400 qcam_set_ack(q, 0);
401 if (qcam_await_ready1(q, 1)) {
402 qc_setup(q);
403 return -EIO;
404 }
405 qcam_set_ack(q, 1);
406 if (qcam_await_ready1(q, 0)) {
407 qc_setup(q);
408 return -EIO;
409 }
410 }
411
412 wantlen = lines * pixelsperline * 24 / 8;
413
414 while (wantlen)
415 {
416 size_t t, s;
417 s = (wantlen > BUFSZ)?BUFSZ:wantlen;
418 t = qcam_read_bytes(q, tmpbuf, s);
419 if (outptr < len)
420 {
421 size_t sz = len - outptr;
422 if (sz > t) sz = t;
423 if (__copy_to_user(buf+outptr, tmpbuf, sz))
424 break;
425 outptr += sz;
426 }
427 wantlen -= t;
428 if (t < s)
429 break;
430 cond_resched();
431 }
432
433 len = outptr;
434
435 if (wantlen)
436 {
437 printk("qcam: short read.\n");
438 if (is_bi_dir)
439 parport_data_forward(q->pport);
440 qc_setup(q);
441 return len;
442 }
443
444 if (is_bi_dir)
445 {
446 int l;
447 do {
448 l = qcam_read_bytes(q, tmpbuf, 3);
449 cond_resched();
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 cond_resched();
482 } while (l && tmpbuf[0] == 0x7e);
483 l = qcam_read_bytes(q, tmpbuf+1, 2);
484 if (force_rgb) {
485 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
486 printk("qcam: bad EOF\n");
487 } else {
488 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
489 printk("qcam: bad EOF\n");
490 }
491 }
492
493 qcam_write_data(q, 0);
494 return len;
495}
496
497/*
498 * Video4linux interfacing
499 */
500
501static int qcam_do_ioctl(struct inode *inode, struct file *file,
502 unsigned int cmd, void *arg)
503{
504 struct video_device *dev = video_devdata(file);
505 struct qcam_device *qcam=(struct qcam_device *)dev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 switch(cmd)
508 {
509 case VIDIOCGCAP:
510 {
511 struct video_capability *b = arg;
512 strcpy(b->name, "Quickcam");
513 b->type = VID_TYPE_CAPTURE|VID_TYPE_SCALES;
514 b->channels = 1;
515 b->audios = 0;
516 b->maxwidth = 320;
517 b->maxheight = 240;
518 b->minwidth = 80;
519 b->minheight = 60;
520 return 0;
521 }
522 case VIDIOCGCHAN:
523 {
524 struct video_channel *v = arg;
525 if(v->channel!=0)
526 return -EINVAL;
527 v->flags=0;
528 v->tuners=0;
529 /* Good question.. its composite or SVHS so.. */
530 v->type = VIDEO_TYPE_CAMERA;
531 strcpy(v->name, "Camera");
532 return 0;
533 }
534 case VIDIOCSCHAN:
535 {
536 struct video_channel *v = arg;
537 if(v->channel!=0)
538 return -EINVAL;
539 return 0;
540 }
541 case VIDIOCGTUNER:
542 {
543 struct video_tuner *v = arg;
544 if(v->tuner)
545 return -EINVAL;
546 memset(v,0,sizeof(*v));
547 strcpy(v->name, "Format");
548 v->mode = VIDEO_MODE_AUTO;
549 return 0;
550 }
551 case VIDIOCSTUNER:
552 {
553 struct video_tuner *v = arg;
554 if(v->tuner)
555 return -EINVAL;
556 if(v->mode!=VIDEO_MODE_AUTO)
557 return -EINVAL;
558 return 0;
559 }
560 case VIDIOCGPICT:
561 {
562 struct video_picture *p = arg;
563 p->colour=0x8000;
564 p->hue=0x8000;
565 p->brightness=qcam->brightness<<8;
566 p->contrast=qcam->contrast<<8;
567 p->whiteness=qcam->whitebal<<8;
568 p->depth=24;
569 p->palette=VIDEO_PALETTE_RGB24;
570 return 0;
571 }
572 case VIDIOCSPICT:
573 {
574 struct video_picture *p = arg;
575
576 /*
577 * Sanity check args
578 */
579 if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24)
580 return -EINVAL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 /*
583 * Now load the camera.
584 */
585 qcam->brightness = p->brightness>>8;
586 qcam->contrast = p->contrast>>8;
587 qcam->whitebal = p->whiteness>>8;
588
Ingo Molnar3593cab2006-02-07 06:49:14 -0200589 mutex_lock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 parport_claim_or_block(qcam->pdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300591 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 parport_release(qcam->pdev);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200593 mutex_unlock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 return 0;
595 }
596 case VIDIOCSWIN:
597 {
598 struct video_window *vw = arg;
599
600 if(vw->flags)
601 return -EINVAL;
602 if(vw->clipcount)
603 return -EINVAL;
604 if(vw->height<60||vw->height>240)
605 return -EINVAL;
606 if(vw->width<80||vw->width>320)
607 return -EINVAL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 qcam->width = 80;
610 qcam->height = 60;
611 qcam->mode = QC_DECIMATION_4;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300612
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 if(vw->width>=160 && vw->height>=120)
614 {
615 qcam->width = 160;
616 qcam->height = 120;
617 qcam->mode = QC_DECIMATION_2;
618 }
619 if(vw->width>=320 && vw->height>=240)
620 {
621 qcam->width = 320;
622 qcam->height = 240;
623 qcam->mode = QC_DECIMATION_1;
624 }
625 qcam->mode |= QC_MILLIONS;
626#if 0
627 if(vw->width>=640 && vw->height>=480)
628 {
629 qcam->width = 640;
630 qcam->height = 480;
631 qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
632 }
633#endif
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300634 /* Ok we figured out what to use from our
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 wide choice */
Ingo Molnar3593cab2006-02-07 06:49:14 -0200636 mutex_lock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 parport_claim_or_block(qcam->pdev);
638 qc_setup(qcam);
639 parport_release(qcam->pdev);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200640 mutex_unlock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 return 0;
642 }
643 case VIDIOCGWIN:
644 {
645 struct video_window *vw = arg;
646 memset(vw, 0, sizeof(*vw));
647 vw->width=qcam->width;
648 vw->height=qcam->height;
649 return 0;
650 }
651 case VIDIOCKEY:
652 return 0;
653 case VIDIOCCAPTURE:
654 case VIDIOCGFBUF:
655 case VIDIOCSFBUF:
656 case VIDIOCGFREQ:
657 case VIDIOCSFREQ:
658 case VIDIOCGAUDIO:
659 case VIDIOCSAUDIO:
660 return -EINVAL;
661 default:
662 return -ENOIOCTLCMD;
663 }
664 return 0;
665}
666
667static int qcam_ioctl(struct inode *inode, struct file *file,
668 unsigned int cmd, unsigned long arg)
669{
670 return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl);
671}
672
673static ssize_t qcam_read(struct file *file, char __user *buf,
674 size_t count, loff_t *ppos)
675{
676 struct video_device *v = video_devdata(file);
677 struct qcam_device *qcam=(struct qcam_device *)v;
678 int len;
679
Ingo Molnar3593cab2006-02-07 06:49:14 -0200680 mutex_lock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 parport_claim_or_block(qcam->pdev);
682 /* Probably should have a semaphore against multiple users */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300683 len = qc_capture(qcam, buf,count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 parport_release(qcam->pdev);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200685 mutex_unlock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 return len;
687}
688
689/* video device template */
Arjan van de Venfa027c22007-02-12 00:55:33 -0800690static const struct file_operations qcam_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 .owner = THIS_MODULE,
692 .open = video_exclusive_open,
693 .release = video_exclusive_release,
694 .ioctl = qcam_ioctl,
Douglas Schilling Landgraf078ff792008-04-22 14:46:11 -0300695#ifdef CONFIG_COMPAT
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200696 .compat_ioctl = v4l_compat_ioctl32,
Douglas Schilling Landgraf078ff792008-04-22 14:46:11 -0300697#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 .read = qcam_read,
699 .llseek = no_llseek,
700};
701
702static struct video_device qcam_template=
703{
704 .owner = THIS_MODULE,
705 .name = "Colour QuickCam",
706 .type = VID_TYPE_CAPTURE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 .fops = &qcam_fops,
708};
709
710/* Initialize the QuickCam driver control structure. */
711
712static struct qcam_device *qcam_init(struct parport *port)
713{
714 struct qcam_device *q;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
717 if(q==NULL)
718 return NULL;
719
720 q->pport = port;
721 q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
722 NULL, 0, NULL);
723
724 q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0;
725
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300726 if (q->pdev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 {
728 printk(KERN_ERR "c-qcam: couldn't register for %s.\n",
729 port->name);
730 kfree(q);
731 return NULL;
732 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
735
Ingo Molnar3593cab2006-02-07 06:49:14 -0200736 mutex_init(&q->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 q->width = q->ccd_width = 320;
738 q->height = q->ccd_height = 240;
739 q->mode = QC_MILLIONS | QC_DECIMATION_1;
740 q->contrast = 192;
741 q->brightness = 240;
742 q->whitebal = 128;
743 q->top = 1;
744 q->left = 14;
745 return q;
746}
747
748static struct qcam_device *qcams[MAX_CAMS];
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300749static unsigned int num_cams;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
751static int init_cqcam(struct parport *port)
752{
753 struct qcam_device *qcam;
754
755 if (parport[0] != -1)
756 {
757 /* The user gave specific instructions */
758 int i, found = 0;
759 for (i = 0; i < MAX_CAMS && parport[i] != -1; i++)
760 {
761 if (parport[0] == port->number)
762 found = 1;
763 }
764 if (!found)
765 return -ENODEV;
766 }
767
768 if (num_cams == MAX_CAMS)
769 return -ENOSPC;
770
771 qcam = qcam_init(port);
772 if (qcam==NULL)
773 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 parport_claim_or_block(qcam->pdev);
776
777 qc_reset(qcam);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 if (probe && qc_detect(qcam)==0)
780 {
781 parport_release(qcam->pdev);
782 parport_unregister_device(qcam->pdev);
783 kfree(qcam);
784 return -ENODEV;
785 }
786
787 qc_setup(qcam);
788
789 parport_release(qcam->pdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
792 {
793 printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
794 qcam->pport->name);
795 parport_unregister_device(qcam->pdev);
796 kfree(qcam);
797 return -ENODEV;
798 }
799
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300800 printk(KERN_INFO "video%d: Colour QuickCam found on %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 qcam->vdev.minor, qcam->pport->name);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 qcams[num_cams++] = qcam;
804
805 return 0;
806}
807
808static void close_cqcam(struct qcam_device *qcam)
809{
810 video_unregister_device(&qcam->vdev);
811 parport_unregister_device(qcam->pdev);
812 kfree(qcam);
813}
814
815static void cq_attach(struct parport *port)
816{
817 init_cqcam(port);
818}
819
820static void cq_detach(struct parport *port)
821{
822 /* Write this some day. */
823}
824
825static struct parport_driver cqcam_driver = {
826 .name = "cqcam",
827 .attach = cq_attach,
828 .detach = cq_detach,
829};
830
831static int __init cqcam_init (void)
832{
833 printk(BANNER "\n");
834
835 return parport_register_driver(&cqcam_driver);
836}
837
838static void __exit cqcam_cleanup (void)
839{
840 unsigned int i;
841
842 for (i = 0; i < num_cams; i++)
843 close_cqcam(qcams[i]);
844
845 parport_unregister_driver(&cqcam_driver);
846}
847
848MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
849MODULE_DESCRIPTION(BANNER);
850MODULE_LICENSE("GPL");
851
852/* FIXME: parport=auto would never have worked, surely? --RR */
853MODULE_PARM_DESC(parport ,"parport=<auto|n[,n]...> for port detection method\n\
854probe=<0|1|2> for camera detection method\n\
855force_rgb=<0|1> for RGB data format (default BGR)");
856module_param_array(parport, int, NULL, 0);
857module_param(probe, int, 0);
858module_param(force_rgb, bool, 0);
859module_param(video_nr, int, 0);
860
861module_init(cqcam_init);
862module_exit(cqcam_cleanup);