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