1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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/mutex.h>
37#include <linux/jiffies.h>
38#include <linux/videodev2.h>
39#include <asm/uaccess.h>
40#include <media/v4l2-device.h>
41#include <media/v4l2-common.h>
42#include <media/v4l2-ioctl.h>
43#include <media/v4l2-fh.h>
44#include <media/v4l2-ctrls.h>
45#include <media/v4l2-event.h>
46
47struct qcam {
48 struct v4l2_device v4l2_dev;
49 struct video_device vdev;
50 struct v4l2_ctrl_handler hdl;
51 struct pardevice *pdev;
52 struct parport *pport;
53 int width, height;
54 int ccd_width, ccd_height;
55 int mode;
56 int contrast, brightness, whitebal;
57 int top, left;
58 unsigned int bidirectional;
59 struct mutex lock;
60};
61
62
63#define MAX_CAMS 4
64
65
66#define QC_MILLIONS 0x18
67#define QC_BILLIONS 0x10
68#define QC_THOUSANDS 0x08
69
70
71#define QC_DECIMATION_1 0
72#define QC_DECIMATION_2 2
73#define QC_DECIMATION_4 4
74
75#define BANNER "Colour QuickCam for Video4Linux v0.06"
76
77static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
78static int probe = 2;
79static bool force_rgb;
80static int video_nr = -1;
81
82
83MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
84 "probe=<0|1|2> for camera detection method\n"
85 "force_rgb=<0|1> for RGB data format (default BGR)");
86module_param_array(parport, int, NULL, 0);
87module_param(probe, int, 0);
88module_param(force_rgb, bool, 0);
89module_param(video_nr, int, 0);
90
91static struct qcam *qcams[MAX_CAMS];
92static unsigned int num_cams;
93
94static inline void qcam_set_ack(struct qcam *qcam, unsigned int i)
95{
96
97
98 parport_frob_control(qcam->pport, 8, i ? 8 : 0);
99}
100
101static inline unsigned int qcam_ready1(struct qcam *qcam)
102{
103 return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0;
104}
105
106static inline unsigned int qcam_ready2(struct qcam *qcam)
107{
108 return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0;
109}
110
111static unsigned int qcam_await_ready1(struct qcam *qcam, int value)
112{
113 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
114 unsigned long oldjiffies = jiffies;
115 unsigned int i;
116
117 for (oldjiffies = jiffies;
118 time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
119 if (qcam_ready1(qcam) == value)
120 return 0;
121
122
123
124 for (i = 0; i < 50; i++) {
125 if (qcam_ready1(qcam) == value)
126 return 0;
127 msleep_interruptible(100);
128 }
129
130
131 v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value,
132 parport_read_status(qcam->pport),
133 parport_read_control(qcam->pport));
134 return 1;
135}
136
137static unsigned int qcam_await_ready2(struct qcam *qcam, int value)
138{
139 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
140 unsigned long oldjiffies = jiffies;
141 unsigned int i;
142
143 for (oldjiffies = jiffies;
144 time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
145 if (qcam_ready2(qcam) == value)
146 return 0;
147
148
149
150 for (i = 0; i < 50; i++) {
151 if (qcam_ready2(qcam) == value)
152 return 0;
153 msleep_interruptible(100);
154 }
155
156
157 v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value,
158 parport_read_status(qcam->pport),
159 parport_read_control(qcam->pport),
160 parport_read_data(qcam->pport));
161 return 1;
162}
163
164static int qcam_read_data(struct qcam *qcam)
165{
166 unsigned int idata;
167
168 qcam_set_ack(qcam, 0);
169 if (qcam_await_ready1(qcam, 1))
170 return -1;
171 idata = parport_read_status(qcam->pport) & 0xf0;
172 qcam_set_ack(qcam, 1);
173 if (qcam_await_ready1(qcam, 0))
174 return -1;
175 idata |= parport_read_status(qcam->pport) >> 4;
176 return idata;
177}
178
179static int qcam_write_data(struct qcam *qcam, unsigned int data)
180{
181 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
182 unsigned int idata;
183
184 parport_write_data(qcam->pport, data);
185 idata = qcam_read_data(qcam);
186 if (data != idata) {
187 v4l2_warn(v4l2_dev, "sent %x but received %x\n", data,
188 idata);
189 return 1;
190 }
191 return 0;
192}
193
194static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data)
195{
196 if (qcam_write_data(qcam, cmd))
197 return -1;
198 if (qcam_write_data(qcam, data))
199 return -1;
200 return 0;
201}
202
203static inline int qcam_get(struct qcam *qcam, unsigned int cmd)
204{
205 if (qcam_write_data(qcam, cmd))
206 return -1;
207 return qcam_read_data(qcam);
208}
209
210static int qc_detect(struct qcam *qcam)
211{
212 unsigned int stat, ostat, i, count = 0;
213
214
215
216
217
218
219 if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA
220 && qcam->pport->probe_info[0].model
221 && !strcmp(qcam->pdev->port->probe_info[0].model,
222 "Color QuickCam 2.0")) {
223 printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
224 return 1;
225 }
226
227 if (probe < 2)
228 return 0;
229
230 parport_write_control(qcam->pport, 0xc);
231
232
233 ostat = stat = parport_read_status(qcam->pport);
234 for (i = 0; i < 250; i++) {
235 mdelay(1);
236 stat = parport_read_status(qcam->pport);
237 if (ostat != stat) {
238 if (++count >= 3)
239 return 1;
240 ostat = stat;
241 }
242 }
243
244
245 parport_write_control(qcam->pport, 0xc);
246 parport_write_control(qcam->pport, 0x8);
247 mdelay(1);
248 parport_write_control(qcam->pport, 0xc);
249 mdelay(1);
250 count = 0;
251
252 ostat = stat = parport_read_status(qcam->pport);
253 for (i = 0; i < 250; i++) {
254 mdelay(1);
255 stat = parport_read_status(qcam->pport);
256 if (ostat != stat) {
257 if (++count >= 3)
258 return 1;
259 ostat = stat;
260 }
261 }
262
263
264 return 0;
265}
266
267static void qc_reset(struct qcam *qcam)
268{
269 parport_write_control(qcam->pport, 0xc);
270 parport_write_control(qcam->pport, 0x8);
271 mdelay(1);
272 parport_write_control(qcam->pport, 0xc);
273 mdelay(1);
274}
275
276
277
278
279static void qc_setup(struct qcam *qcam)
280{
281 qc_reset(qcam);
282
283
284 qcam_set(qcam, 11, qcam->brightness);
285
286
287
288 qcam_set(qcam, 17, qcam->ccd_height);
289 qcam_set(qcam, 19, qcam->ccd_width / 2);
290
291
292 qcam_set(qcam, 0xd, qcam->top);
293 qcam_set(qcam, 0xf, qcam->left);
294
295
296 qcam_set(qcam, 0x19, qcam->contrast);
297 qcam_set(qcam, 0x1f, qcam->whitebal);
298
299
300 qcam_set(qcam, 45, 2);
301}
302
303
304
305
306
307static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes)
308{
309 unsigned int bytes = 0;
310
311 qcam_set_ack(qcam, 0);
312 if (qcam->bidirectional) {
313
314 while (bytes < nbytes) {
315 unsigned int lo1, hi1, lo2, hi2;
316 unsigned char r, g, b;
317
318 if (qcam_await_ready2(qcam, 1))
319 return bytes;
320 lo1 = parport_read_data(qcam->pport) >> 1;
321 hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
322 qcam_set_ack(qcam, 1);
323 if (qcam_await_ready2(qcam, 0))
324 return bytes;
325 lo2 = parport_read_data(qcam->pport) >> 1;
326 hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
327 qcam_set_ack(qcam, 0);
328 r = lo1 | ((hi1 & 1) << 7);
329 g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
330 b = lo2 | ((hi2 & 1) << 7);
331 if (force_rgb) {
332 buf[bytes++] = r;
333 buf[bytes++] = g;
334 buf[bytes++] = b;
335 } else {
336 buf[bytes++] = b;
337 buf[bytes++] = g;
338 buf[bytes++] = r;
339 }
340 }
341 } else {
342
343 int i = 0, n = bytes;
344 unsigned char rgb[3];
345
346 while (bytes < nbytes) {
347 unsigned int hi, lo;
348
349 if (qcam_await_ready1(qcam, 1))
350 return bytes;
351 hi = (parport_read_status(qcam->pport) & 0xf0);
352 qcam_set_ack(qcam, 1);
353 if (qcam_await_ready1(qcam, 0))
354 return bytes;
355 lo = (parport_read_status(qcam->pport) & 0xf0);
356 qcam_set_ack(qcam, 0);
357
358 rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
359 if (i >= 2) {
360get_fragment:
361 if (force_rgb) {
362 buf[n++] = rgb[0];
363 buf[n++] = rgb[1];
364 buf[n++] = rgb[2];
365 } else {
366 buf[n++] = rgb[2];
367 buf[n++] = rgb[1];
368 buf[n++] = rgb[0];
369 }
370 }
371 }
372 if (i) {
373 i = 0;
374 goto get_fragment;
375 }
376 }
377 return bytes;
378}
379
380#define BUFSZ 150
381
382static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len)
383{
384 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
385 unsigned lines, pixelsperline;
386 unsigned int is_bi_dir = qcam->bidirectional;
387 size_t wantlen, outptr = 0;
388 char tmpbuf[BUFSZ];
389
390 if (!access_ok(VERIFY_WRITE, buf, len))
391 return -EFAULT;
392
393
394 for (;;) {
395 int i = qcam_get(qcam, 41);
396
397 if (i == -1) {
398 qc_setup(qcam);
399 return -EIO;
400 }
401 if ((i & 0x80) == 0)
402 break;
403 schedule();
404 }
405
406 if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1))
407 return -EIO;
408
409 lines = qcam->height;
410 pixelsperline = qcam->width;
411
412 if (is_bi_dir) {
413
414 parport_data_reverse(qcam->pport);
415 mdelay(3);
416 qcam_set_ack(qcam, 0);
417 if (qcam_await_ready1(qcam, 1)) {
418 qc_setup(qcam);
419 return -EIO;
420 }
421 qcam_set_ack(qcam, 1);
422 if (qcam_await_ready1(qcam, 0)) {
423 qc_setup(qcam);
424 return -EIO;
425 }
426 }
427
428 wantlen = lines * pixelsperline * 24 / 8;
429
430 while (wantlen) {
431 size_t t, s;
432
433 s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
434 t = qcam_read_bytes(qcam, tmpbuf, s);
435 if (outptr < len) {
436 size_t sz = len - outptr;
437
438 if (sz > t)
439 sz = t;
440 if (__copy_to_user(buf + outptr, tmpbuf, sz))
441 break;
442 outptr += sz;
443 }
444 wantlen -= t;
445 if (t < s)
446 break;
447 cond_resched();
448 }
449
450 len = outptr;
451
452 if (wantlen) {
453 v4l2_err(v4l2_dev, "short read.\n");
454 if (is_bi_dir)
455 parport_data_forward(qcam->pport);
456 qc_setup(qcam);
457 return len;
458 }
459
460 if (is_bi_dir) {
461 int l;
462
463 do {
464 l = qcam_read_bytes(qcam, tmpbuf, 3);
465 cond_resched();
466 } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
467 if (force_rgb) {
468 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
469 v4l2_err(v4l2_dev, "bad EOF\n");
470 } else {
471 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
472 v4l2_err(v4l2_dev, "bad EOF\n");
473 }
474 qcam_set_ack(qcam, 0);
475 if (qcam_await_ready1(qcam, 1)) {
476 v4l2_err(v4l2_dev, "no ack after EOF\n");
477 parport_data_forward(qcam->pport);
478 qc_setup(qcam);
479 return len;
480 }
481 parport_data_forward(qcam->pport);
482 mdelay(3);
483 qcam_set_ack(qcam, 1);
484 if (qcam_await_ready1(qcam, 0)) {
485 v4l2_err(v4l2_dev, "no ack to port turnaround\n");
486 qc_setup(qcam);
487 return len;
488 }
489 } else {
490 int l;
491
492 do {
493 l = qcam_read_bytes(qcam, tmpbuf, 1);
494 cond_resched();
495 } while (l && tmpbuf[0] == 0x7e);
496 l = qcam_read_bytes(qcam, tmpbuf + 1, 2);
497 if (force_rgb) {
498 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
499 v4l2_err(v4l2_dev, "bad EOF\n");
500 } else {
501 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
502 v4l2_err(v4l2_dev, "bad EOF\n");
503 }
504 }
505
506 qcam_write_data(qcam, 0);
507 return len;
508}
509
510
511
512
513
514static int qcam_querycap(struct file *file, void *priv,
515 struct v4l2_capability *vcap)
516{
517 struct qcam *qcam = video_drvdata(file);
518
519 strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
520 strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card));
521 strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
522 vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
523 vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
524 return 0;
525}
526
527static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
528{
529 if (vin->index > 0)
530 return -EINVAL;
531 strlcpy(vin->name, "Camera", sizeof(vin->name));
532 vin->type = V4L2_INPUT_TYPE_CAMERA;
533 vin->audioset = 0;
534 vin->tuner = 0;
535 vin->std = 0;
536 vin->status = 0;
537 return 0;
538}
539
540static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
541{
542 *inp = 0;
543 return 0;
544}
545
546static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
547{
548 return (inp > 0) ? -EINVAL : 0;
549}
550
551static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
552{
553 struct qcam *qcam = video_drvdata(file);
554 struct v4l2_pix_format *pix = &fmt->fmt.pix;
555
556 pix->width = qcam->width;
557 pix->height = qcam->height;
558 pix->pixelformat = V4L2_PIX_FMT_RGB24;
559 pix->field = V4L2_FIELD_NONE;
560 pix->bytesperline = 3 * qcam->width;
561 pix->sizeimage = 3 * qcam->width * qcam->height;
562
563 pix->colorspace = V4L2_COLORSPACE_SRGB;
564 return 0;
565}
566
567static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
568{
569 struct v4l2_pix_format *pix = &fmt->fmt.pix;
570
571 if (pix->height < 60 || pix->width < 80) {
572 pix->height = 60;
573 pix->width = 80;
574 } else if (pix->height < 120 || pix->width < 160) {
575 pix->height = 120;
576 pix->width = 160;
577 } else {
578 pix->height = 240;
579 pix->width = 320;
580 }
581 pix->pixelformat = V4L2_PIX_FMT_RGB24;
582 pix->field = V4L2_FIELD_NONE;
583 pix->bytesperline = 3 * pix->width;
584 pix->sizeimage = 3 * pix->width * pix->height;
585
586 pix->colorspace = V4L2_COLORSPACE_SRGB;
587 return 0;
588}
589
590static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
591{
592 struct qcam *qcam = video_drvdata(file);
593 struct v4l2_pix_format *pix = &fmt->fmt.pix;
594 int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
595
596 if (ret)
597 return ret;
598 switch (pix->height) {
599 case 60:
600 qcam->mode = QC_DECIMATION_4;
601 break;
602 case 120:
603 qcam->mode = QC_DECIMATION_2;
604 break;
605 default:
606 qcam->mode = QC_DECIMATION_1;
607 break;
608 }
609
610 mutex_lock(&qcam->lock);
611 qcam->mode |= QC_MILLIONS;
612 qcam->height = pix->height;
613 qcam->width = pix->width;
614 parport_claim_or_block(qcam->pdev);
615 qc_setup(qcam);
616 parport_release(qcam->pdev);
617 mutex_unlock(&qcam->lock);
618 return 0;
619}
620
621static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
622{
623 static struct v4l2_fmtdesc formats[] = {
624 { 0, 0, 0,
625 "RGB 8:8:8", V4L2_PIX_FMT_RGB24,
626 { 0, 0, 0, 0 }
627 },
628 };
629 enum v4l2_buf_type type = fmt->type;
630
631 if (fmt->index > 0)
632 return -EINVAL;
633
634 *fmt = formats[fmt->index];
635 fmt->type = type;
636 return 0;
637}
638
639static ssize_t qcam_read(struct file *file, char __user *buf,
640 size_t count, loff_t *ppos)
641{
642 struct qcam *qcam = video_drvdata(file);
643 int len;
644
645 mutex_lock(&qcam->lock);
646 parport_claim_or_block(qcam->pdev);
647
648 len = qc_capture(qcam, buf, count);
649 parport_release(qcam->pdev);
650 mutex_unlock(&qcam->lock);
651 return len;
652}
653
654static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
655{
656 struct qcam *qcam =
657 container_of(ctrl->handler, struct qcam, hdl);
658 int ret = 0;
659
660 mutex_lock(&qcam->lock);
661 switch (ctrl->id) {
662 case V4L2_CID_BRIGHTNESS:
663 qcam->brightness = ctrl->val;
664 break;
665 case V4L2_CID_CONTRAST:
666 qcam->contrast = ctrl->val;
667 break;
668 case V4L2_CID_GAMMA:
669 qcam->whitebal = ctrl->val;
670 break;
671 default:
672 ret = -EINVAL;
673 break;
674 }
675 if (ret == 0) {
676 parport_claim_or_block(qcam->pdev);
677 qc_setup(qcam);
678 parport_release(qcam->pdev);
679 }
680 mutex_unlock(&qcam->lock);
681 return ret;
682}
683
684static const struct v4l2_file_operations qcam_fops = {
685 .owner = THIS_MODULE,
686 .open = v4l2_fh_open,
687 .release = v4l2_fh_release,
688 .poll = v4l2_ctrl_poll,
689 .unlocked_ioctl = video_ioctl2,
690 .read = qcam_read,
691};
692
693static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
694 .vidioc_querycap = qcam_querycap,
695 .vidioc_g_input = qcam_g_input,
696 .vidioc_s_input = qcam_s_input,
697 .vidioc_enum_input = qcam_enum_input,
698 .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
699 .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
700 .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
701 .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap,
702 .vidioc_log_status = v4l2_ctrl_log_status,
703 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
704 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
705};
706
707static const struct v4l2_ctrl_ops qcam_ctrl_ops = {
708 .s_ctrl = qcam_s_ctrl,
709};
710
711
712
713static struct qcam *qcam_init(struct parport *port)
714{
715 struct qcam *qcam;
716 struct v4l2_device *v4l2_dev;
717
718 qcam = kzalloc(sizeof(*qcam), GFP_KERNEL);
719 if (qcam == NULL)
720 return NULL;
721
722 v4l2_dev = &qcam->v4l2_dev;
723 strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name));
724
725 if (v4l2_device_register(NULL, v4l2_dev) < 0) {
726 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
727 kfree(qcam);
728 return NULL;
729 }
730
731 v4l2_ctrl_handler_init(&qcam->hdl, 3);
732 v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
733 V4L2_CID_BRIGHTNESS, 0, 255, 1, 240);
734 v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
735 V4L2_CID_CONTRAST, 0, 255, 1, 192);
736 v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
737 V4L2_CID_GAMMA, 0, 255, 1, 128);
738 if (qcam->hdl.error) {
739 v4l2_err(v4l2_dev, "couldn't register controls\n");
740 v4l2_ctrl_handler_free(&qcam->hdl);
741 kfree(qcam);
742 return NULL;
743 }
744
745 qcam->pport = port;
746 qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
747 NULL, 0, NULL);
748
749 qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
750
751 if (qcam->pdev == NULL) {
752 v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
753 v4l2_ctrl_handler_free(&qcam->hdl);
754 kfree(qcam);
755 return NULL;
756 }
757
758 strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name));
759 qcam->vdev.v4l2_dev = v4l2_dev;
760 qcam->vdev.fops = &qcam_fops;
761 qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
762 qcam->vdev.release = video_device_release_empty;
763 qcam->vdev.ctrl_handler = &qcam->hdl;
764 set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
765 video_set_drvdata(&qcam->vdev, qcam);
766
767 mutex_init(&qcam->lock);
768 qcam->width = qcam->ccd_width = 320;
769 qcam->height = qcam->ccd_height = 240;
770 qcam->mode = QC_MILLIONS | QC_DECIMATION_1;
771 qcam->contrast = 192;
772 qcam->brightness = 240;
773 qcam->whitebal = 128;
774 qcam->top = 1;
775 qcam->left = 14;
776 return qcam;
777}
778
779static int init_cqcam(struct parport *port)
780{
781 struct qcam *qcam;
782 struct v4l2_device *v4l2_dev;
783
784 if (parport[0] != -1) {
785
786 int i, found = 0;
787
788 for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) {
789 if (parport[0] == port->number)
790 found = 1;
791 }
792 if (!found)
793 return -ENODEV;
794 }
795
796 if (num_cams == MAX_CAMS)
797 return -ENOSPC;
798
799 qcam = qcam_init(port);
800 if (qcam == NULL)
801 return -ENODEV;
802
803 v4l2_dev = &qcam->v4l2_dev;
804
805 parport_claim_or_block(qcam->pdev);
806
807 qc_reset(qcam);
808
809 if (probe && qc_detect(qcam) == 0) {
810 parport_release(qcam->pdev);
811 parport_unregister_device(qcam->pdev);
812 kfree(qcam);
813 return -ENODEV;
814 }
815
816 qc_setup(qcam);
817
818 parport_release(qcam->pdev);
819
820 if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
821 v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n",
822 qcam->pport->name);
823 parport_unregister_device(qcam->pdev);
824 kfree(qcam);
825 return -ENODEV;
826 }
827
828 v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n",
829 video_device_node_name(&qcam->vdev), qcam->pport->name);
830
831 qcams[num_cams++] = qcam;
832
833 return 0;
834}
835
836static void close_cqcam(struct qcam *qcam)
837{
838 video_unregister_device(&qcam->vdev);
839 v4l2_ctrl_handler_free(&qcam->hdl);
840 parport_unregister_device(qcam->pdev);
841 kfree(qcam);
842}
843
844static void cq_attach(struct parport *port)
845{
846 init_cqcam(port);
847}
848
849static void cq_detach(struct parport *port)
850{
851
852}
853
854static struct parport_driver cqcam_driver = {
855 .name = "cqcam",
856 .attach = cq_attach,
857 .detach = cq_detach,
858};
859
860static int __init cqcam_init(void)
861{
862 printk(KERN_INFO BANNER "\n");
863
864 return parport_register_driver(&cqcam_driver);
865}
866
867static void __exit cqcam_cleanup(void)
868{
869 unsigned int i;
870
871 for (i = 0; i < num_cams; i++)
872 close_cqcam(qcams[i]);
873
874 parport_unregister_driver(&cqcam_driver);
875}
876
877MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
878MODULE_DESCRIPTION(BANNER);
879MODULE_LICENSE("GPL");
880MODULE_VERSION("0.0.4");
881
882module_init(cqcam_init);
883module_exit(cqcam_cleanup);
884