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