1/* 2 * USB ViCam WebCam driver 3 * Copyright (c) 2002 Joe Burks (jburks@wavicle.org), 4 * Christopher L Cheney (ccheney@cheney.cx), 5 * Pavel Machek (pavel@ucw.cz), 6 * John Tyner (jtyner@cs.ucr.edu), 7 * Monroe Williams (monroe@pobox.com) 8 * 9 * Supports 3COM HomeConnect PC Digital WebCam 10 * Supports Compro PS39U WebCam 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 * 26 * This source code is based heavily on the CPiA webcam driver which was 27 * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt 28 * 29 * Portions of this code were also copied from usbvideo.c 30 * 31 * Special thanks to the whole team at Sourceforge for help making 32 * this driver become a reality. Notably: 33 * Andy Armstrong who reverse engineered the color encoding and 34 * Pavel Machek and Chris Cheney who worked on reverse engineering the 35 * camera controls and wrote the first generation driver. 36 */ 37 38#include <linux/kernel.h> 39#include <linux/module.h> 40#include <linux/init.h> 41#include <linux/videodev.h> 42#include <linux/usb.h> 43#include <linux/vmalloc.h> 44#include <linux/mm.h> 45#include <linux/slab.h> 46#include <linux/smp_lock.h> 47#include <linux/mutex.h> 48#include <linux/firmware.h> 49#include <linux/ihex.h> 50#include "usbvideo.h" 51 52// #define VICAM_DEBUG 53 54#ifdef VICAM_DEBUG 55#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __func__, lineno, ##args) 56#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args) 57#else 58#define DBG(fmn,args...) do {} while(0) 59#endif 60 61#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org" 62#define DRIVER_DESC "ViCam WebCam Driver" 63 64/* Define these values to match your device */ 65#define USB_VICAM_VENDOR_ID 0x04c1 66#define USB_VICAM_PRODUCT_ID 0x009d 67#define USB_COMPRO_VENDOR_ID 0x0602 68#define USB_COMPRO_PRODUCT_ID 0x1001 69 70#define VICAM_BYTES_PER_PIXEL 3 71#define VICAM_MAX_READ_SIZE (512*242+128) 72#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240) 73#define VICAM_FRAMES 2 74 75#define VICAM_HEADER_SIZE 64 76 77/* rvmalloc / rvfree copied from usbvideo.c 78 * 79 * Not sure why these are not yet non-statics which I can reference through 80 * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime 81 * in the future. 82 * 83*/ 84static void *rvmalloc(unsigned long size) 85{ 86 void *mem; 87 unsigned long adr; 88 89 size = PAGE_ALIGN(size); 90 mem = vmalloc_32(size); 91 if (!mem) 92 return NULL; 93 94 memset(mem, 0, size); /* Clear the ram out, no junk to the user */ 95 adr = (unsigned long) mem; 96 while (size > 0) { 97 SetPageReserved(vmalloc_to_page((void *)adr)); 98 adr += PAGE_SIZE; 99 size -= PAGE_SIZE; 100 } 101 102 return mem; 103} 104 105static void rvfree(void *mem, unsigned long size) 106{ 107 unsigned long adr; 108 109 if (!mem) 110 return; 111 112 adr = (unsigned long) mem; 113 while ((long) size > 0) { 114 ClearPageReserved(vmalloc_to_page((void *)adr)); 115 adr += PAGE_SIZE; 116 size -= PAGE_SIZE; 117 } 118 vfree(mem); 119} 120 121struct vicam_camera { 122 u16 shutter_speed; // capture shutter speed 123 u16 gain; // capture gain 124 125 u8 *raw_image; // raw data captured from the camera 126 u8 *framebuf; // processed data in RGB24 format 127 u8 *cntrlbuf; // area used to send control msgs 128 129 struct video_device vdev; // v4l video device 130 struct usb_device *udev; // usb device 131 132 /* guard against simultaneous accesses to the camera */ 133 struct mutex cam_lock; 134 135 int is_initialized; 136 u8 open_count; 137 u8 bulkEndpoint; 138 int needsDummyRead; 139}; 140 141static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id); 142static void vicam_disconnect(struct usb_interface *intf); 143static void read_frame(struct vicam_camera *cam, int framenum); 144static void vicam_decode_color(const u8 *, u8 *); 145 146static int __send_control_msg(struct vicam_camera *cam, 147 u8 request, 148 u16 value, 149 u16 index, 150 unsigned char *cp, 151 u16 size) 152{ 153 int status; 154 155 /* cp must be memory that has been allocated by kmalloc */ 156 157 status = usb_control_msg(cam->udev, 158 usb_sndctrlpipe(cam->udev, 0), 159 request, 160 USB_DIR_OUT | USB_TYPE_VENDOR | 161 USB_RECIP_DEVICE, value, index, 162 cp, size, 1000); 163 164 status = min(status, 0); 165 166 if (status < 0) { 167 printk(KERN_INFO "Failed sending control message, error %d.\n", 168 status); 169 } 170 171 return status; 172} 173 174static int send_control_msg(struct vicam_camera *cam, 175 u8 request, 176 u16 value, 177 u16 index, 178 unsigned char *cp, 179 u16 size) 180{ 181 int status = -ENODEV; 182 mutex_lock(&cam->cam_lock); 183 if (cam->udev) { 184 status = __send_control_msg(cam, request, value, 185 index, cp, size); 186 } 187 mutex_unlock(&cam->cam_lock); 188 return status; 189} 190static int 191initialize_camera(struct vicam_camera *cam) 192{ 193 int err; 194 const struct ihex_binrec *rec; 195 const struct firmware *uninitialized_var(fw); 196 197 err = request_ihex_firmware(&fw, "vicam/firmware.fw", &cam->udev->dev); 198 if (err) { 199 printk(KERN_ERR "Failed to load \"vicam/firmware.fw\": %d\n", 200 err); 201 return err; 202 } 203 204 for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { 205 memcpy(cam->cntrlbuf, rec->data, be16_to_cpu(rec->len)); 206 207 err = send_control_msg(cam, 0xff, 0, 0, 208 cam->cntrlbuf, be16_to_cpu(rec->len)); 209 if (err) 210 break; 211 } 212 213 release_firmware(fw); 214 215 return err; 216} 217 218static int 219set_camera_power(struct vicam_camera *cam, int state) 220{ 221 int status; 222 223 if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0) 224 return status; 225 226 if (state) { 227 send_control_msg(cam, 0x55, 1, 0, NULL, 0); 228 } 229 230 return 0; 231} 232 233static long 234vicam_ioctl(struct file *file, unsigned int ioctlnr, unsigned long arg) 235{ 236 void __user *user_arg = (void __user *)arg; 237 struct vicam_camera *cam = file->private_data; 238 long retval = 0; 239 240 if (!cam) 241 return -ENODEV; 242 243 switch (ioctlnr) { 244 /* query capabilities */ 245 case VIDIOCGCAP: 246 { 247 struct video_capability b; 248 249 DBG("VIDIOCGCAP\n"); 250 memset(&b, 0, sizeof(b)); 251 strcpy(b.name, "ViCam-based Camera"); 252 b.type = VID_TYPE_CAPTURE; 253 b.channels = 1; 254 b.audios = 0; 255 b.maxwidth = 320; /* VIDEOSIZE_CIF */ 256 b.maxheight = 240; 257 b.minwidth = 320; /* VIDEOSIZE_48_48 */ 258 b.minheight = 240; 259 260 if (copy_to_user(user_arg, &b, sizeof(b))) 261 retval = -EFAULT; 262 263 break; 264 } 265 /* get/set video source - we are a camera and nothing else */ 266 case VIDIOCGCHAN: 267 { 268 struct video_channel v; 269 270 DBG("VIDIOCGCHAN\n"); 271 if (copy_from_user(&v, user_arg, sizeof(v))) { 272 retval = -EFAULT; 273 break; 274 } 275 if (v.channel != 0) { 276 retval = -EINVAL; 277 break; 278 } 279 280 v.channel = 0; 281 strcpy(v.name, "Camera"); 282 v.tuners = 0; 283 v.flags = 0; 284 v.type = VIDEO_TYPE_CAMERA; 285 v.norm = 0; 286 287 if (copy_to_user(user_arg, &v, sizeof(v))) 288 retval = -EFAULT; 289 break; 290 } 291 292 case VIDIOCSCHAN: 293 { 294 int v; 295 296 if (copy_from_user(&v, user_arg, sizeof(v))) 297 retval = -EFAULT; 298 DBG("VIDIOCSCHAN %d\n", v); 299 300 if (retval == 0 && v != 0) 301 retval = -EINVAL; 302 303 break; 304 } 305 306 /* image properties */ 307 case VIDIOCGPICT: 308 { 309 struct video_picture vp; 310 DBG("VIDIOCGPICT\n"); 311 memset(&vp, 0, sizeof (struct video_picture)); 312 vp.brightness = cam->gain << 8; 313 vp.depth = 24; 314 vp.palette = VIDEO_PALETTE_RGB24; 315 if (copy_to_user(user_arg, &vp, sizeof (struct video_picture))) 316 retval = -EFAULT; 317 break; 318 } 319 320 case VIDIOCSPICT: 321 { 322 struct video_picture vp; 323 324 if (copy_from_user(&vp, user_arg, sizeof(vp))) { 325 retval = -EFAULT; 326 break; 327 } 328 329 DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth, 330 vp.palette); 331 332 cam->gain = vp.brightness >> 8; 333 334 if (vp.depth != 24 335 || vp.palette != VIDEO_PALETTE_RGB24) 336 retval = -EINVAL; 337 338 break; 339 } 340 341 /* get/set capture window */ 342 case VIDIOCGWIN: 343 { 344 struct video_window vw; 345 vw.x = 0; 346 vw.y = 0; 347 vw.width = 320; 348 vw.height = 240; 349 vw.chromakey = 0; 350 vw.flags = 0; 351 vw.clips = NULL; 352 vw.clipcount = 0; 353 354 DBG("VIDIOCGWIN\n"); 355 356 if (copy_to_user(user_arg, (void *)&vw, sizeof(vw))) 357 retval = -EFAULT; 358 359 // I'm not sure what the deal with a capture window is, it is very poorly described 360 // in the doc. So I won't support it now. 361 break; 362 } 363 364 case VIDIOCSWIN: 365 { 366 367 struct video_window vw; 368 369 if (copy_from_user(&vw, user_arg, sizeof(vw))) { 370 retval = -EFAULT; 371 break; 372 } 373 374 DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height); 375 376 if ( vw.width != 320 || vw.height != 240 ) 377 retval = -EFAULT; 378 379 break; 380 } 381 382 /* mmap interface */ 383 case VIDIOCGMBUF: 384 { 385 struct video_mbuf vm; 386 int i; 387 388 DBG("VIDIOCGMBUF\n"); 389 memset(&vm, 0, sizeof (vm)); 390 vm.size = 391 VICAM_MAX_FRAME_SIZE * VICAM_FRAMES; 392 vm.frames = VICAM_FRAMES; 393 for (i = 0; i < VICAM_FRAMES; i++) 394 vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i; 395 396 if (copy_to_user(user_arg, (void *)&vm, sizeof(vm))) 397 retval = -EFAULT; 398 399 break; 400 } 401 402 case VIDIOCMCAPTURE: 403 { 404 struct video_mmap vm; 405 // int video_size; 406 407 if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) { 408 retval = -EFAULT; 409 break; 410 } 411 412 DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format); 413 414 if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 ) 415 retval = -EINVAL; 416 417 // in theory right here we'd start the image capturing 418 // (fill in a bulk urb and submit it asynchronously) 419 // 420 // Instead we're going to do a total hack job for now and 421 // retrieve the frame in VIDIOCSYNC 422 423 break; 424 } 425 426 case VIDIOCSYNC: 427 { 428 int frame; 429 430 if (copy_from_user((void *)&frame, user_arg, sizeof(int))) { 431 retval = -EFAULT; 432 break; 433 } 434 DBG("VIDIOCSYNC: %d\n", frame); 435 436 read_frame(cam, frame); 437 vicam_decode_color(cam->raw_image, 438 cam->framebuf + 439 frame * VICAM_MAX_FRAME_SIZE ); 440 441 break; 442 } 443 444 /* pointless to implement overlay with this camera */ 445 case VIDIOCCAPTURE: 446 case VIDIOCGFBUF: 447 case VIDIOCSFBUF: 448 case VIDIOCKEY: 449 retval = -EINVAL; 450 break; 451 452 /* tuner interface - we have none */ 453 case VIDIOCGTUNER: 454 case VIDIOCSTUNER: 455 case VIDIOCGFREQ: 456 case VIDIOCSFREQ: 457 retval = -EINVAL; 458 break; 459 460 /* audio interface - we have none */ 461 case VIDIOCGAUDIO: 462 case VIDIOCSAUDIO: 463 retval = -EINVAL; 464 break; 465 default: 466 retval = -ENOIOCTLCMD; 467 break; 468 } 469 470 return retval; 471} 472 473static int 474vicam_open(struct file *file) 475{ 476 struct vicam_camera *cam = video_drvdata(file); 477 478 DBG("open\n"); 479 480 if (!cam) { 481 printk(KERN_ERR 482 "vicam video_device improperly initialized"); 483 return -EINVAL; 484 } 485 486 /* the videodev_lock held above us protects us from 487 * simultaneous opens...for now. we probably shouldn't 488 * rely on this fact forever. 489 */ 490 491 lock_kernel(); 492 if (cam->open_count > 0) { 493 printk(KERN_INFO 494 "vicam_open called on already opened camera"); 495 unlock_kernel(); 496 return -EBUSY; 497 } 498 499 cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL); 500 if (!cam->raw_image) { 501 unlock_kernel(); 502 return -ENOMEM; 503 } 504 505 cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); 506 if (!cam->framebuf) { 507 kfree(cam->raw_image); 508 unlock_kernel(); 509 return -ENOMEM; 510 } 511 512 cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); 513 if (!cam->cntrlbuf) { 514 kfree(cam->raw_image); 515 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); 516 unlock_kernel(); 517 return -ENOMEM; 518 } 519 520 // First upload firmware, then turn the camera on 521 522 if (!cam->is_initialized) { 523 initialize_camera(cam); 524 525 cam->is_initialized = 1; 526 } 527 528 set_camera_power(cam, 1); 529 530 cam->needsDummyRead = 1; 531 cam->open_count++; 532 533 file->private_data = cam; 534 unlock_kernel(); 535 536 return 0; 537} 538 539static int 540vicam_close(struct file *file) 541{ 542 struct vicam_camera *cam = file->private_data; 543 int open_count; 544 struct usb_device *udev; 545 546 DBG("close\n"); 547 548 /* it's not the end of the world if 549 * we fail to turn the camera off. 550 */ 551 552 set_camera_power(cam, 0); 553 554 kfree(cam->raw_image); 555 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); 556 kfree(cam->cntrlbuf); 557 558 mutex_lock(&cam->cam_lock); 559 560 cam->open_count--; 561 open_count = cam->open_count; 562 udev = cam->udev; 563 564 mutex_unlock(&cam->cam_lock); 565 566 if (!open_count && !udev) { 567 kfree(cam); 568 } 569 570 return 0; 571} 572 573static void vicam_decode_color(const u8 *data, u8 *rgb) 574{ 575 /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB 576 * Copyright (C) 2002 Monroe Williams (monroe@pobox.com) 577 */ 578 579 int i, prevY, nextY; 580 581 prevY = 512; 582 nextY = 512; 583 584 data += VICAM_HEADER_SIZE; 585 586 for( i = 0; i < 240; i++, data += 512 ) { 587 const int y = ( i * 242 ) / 240; 588 589 int j, prevX, nextX; 590 int Y, Cr, Cb; 591 592 if ( y == 242 - 1 ) { 593 nextY = -512; 594 } 595 596 prevX = 1; 597 nextX = 1; 598 599 for ( j = 0; j < 320; j++, rgb += 3 ) { 600 const int x = ( j * 512 ) / 320; 601 const u8 * const src = &data[x]; 602 603 if ( x == 512 - 1 ) { 604 nextX = -1; 605 } 606 607 Cr = ( src[prevX] - src[0] ) + 608 ( src[nextX] - src[0] ); 609 Cr /= 2; 610 611 Cb = ( src[prevY] - src[prevX + prevY] ) + 612 ( src[prevY] - src[nextX + prevY] ) + 613 ( src[nextY] - src[prevX + nextY] ) + 614 ( src[nextY] - src[nextX + nextY] ); 615 Cb /= 4; 616 617 Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 ); 618 619 if ( i & 1 ) { 620 int Ct = Cr; 621 Cr = Cb; 622 Cb = Ct; 623 } 624 625 if ( ( x ^ i ) & 1 ) { 626 Cr = -Cr; 627 Cb = -Cb; 628 } 629 630 rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) + 631 500 ) / 900, 0, 255 ); 632 rgb[1] = clamp( ( ( Y - ( 392 * Cb ) - 633 ( 813 * Cr ) ) + 634 500 ) / 1000, 0, 255 ); 635 rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) + 636 500 ) / 1300, 0, 255 ); 637 638 prevX = -1; 639 } 640 641 prevY = -512; 642 } 643} 644 645static void 646read_frame(struct vicam_camera *cam, int framenum) 647{ 648 unsigned char *request = cam->cntrlbuf; 649 int realShutter; 650 int n; 651 int actual_length; 652 653 if (cam->needsDummyRead) { 654 cam->needsDummyRead = 0; 655 read_frame(cam, framenum); 656 } 657 658 memset(request, 0, 16); 659 request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain 660 661 request[1] = 0; // 512x242 capture 662 663 request[2] = 0x90; // the function of these two bytes 664 request[3] = 0x07; // is not yet understood 665 666 if (cam->shutter_speed > 60) { 667 // Short exposure 668 realShutter = 669 ((-15631900 / cam->shutter_speed) + 260533) / 1000; 670 request[4] = realShutter & 0xFF; 671 request[5] = (realShutter >> 8) & 0xFF; 672 request[6] = 0x03; 673 request[7] = 0x01; 674 } else { 675 // Long exposure 676 realShutter = 15600 / cam->shutter_speed - 1; 677 request[4] = 0; 678 request[5] = 0; 679 request[6] = realShutter & 0xFF; 680 request[7] = realShutter >> 8; 681 } 682 683 // Per John Markus Bj��rndalen, byte at index 8 causes problems if it isn't 0 684 request[8] = 0; 685 // bytes 9-15 do not seem to affect exposure or image quality 686 687 mutex_lock(&cam->cam_lock); 688 689 if (!cam->udev) { 690 goto done; 691 } 692 693 n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16); 694 695 if (n < 0) { 696 printk(KERN_ERR 697 " Problem sending frame capture control message"); 698 goto done; 699 } 700 701 n = usb_bulk_msg(cam->udev, 702 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint), 703 cam->raw_image, 704 512 * 242 + 128, &actual_length, 10000); 705 706 if (n < 0) { 707 printk(KERN_ERR "Problem during bulk read of frame data: %d\n", 708 n); 709 } 710 711 done: 712 mutex_unlock(&cam->cam_lock); 713} 714 715static ssize_t 716vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos ) 717{ 718 struct vicam_camera *cam = file->private_data; 719 720 DBG("read %d bytes.\n", (int) count); 721 722 if (*ppos >= VICAM_MAX_FRAME_SIZE) { 723 *ppos = 0; 724 return 0; 725 } 726 727 if (*ppos == 0) { 728 read_frame(cam, 0); 729 vicam_decode_color(cam->raw_image, 730 cam->framebuf + 731 0 * VICAM_MAX_FRAME_SIZE); 732 } 733 734 count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos); 735 736 if (copy_to_user(buf, &cam->framebuf[*ppos], count)) { 737 count = -EFAULT; 738 } else { 739 *ppos += count; 740 } 741 742 if (count == VICAM_MAX_FRAME_SIZE) { 743 *ppos = 0; 744 } 745 746 return count; 747} 748 749 750static int 751vicam_mmap(struct file *file, struct vm_area_struct *vma) 752{ 753 // TODO: allocate the raw frame buffer if necessary 754 unsigned long page, pos; 755 unsigned long start = vma->vm_start; 756 unsigned long size = vma->vm_end-vma->vm_start; 757 struct vicam_camera *cam = file->private_data; 758 759 if (!cam) 760 return -ENODEV; 761 762 DBG("vicam_mmap: %ld\n", size); 763 764 /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes 765 * to the size the application requested for mmap and it was screwing apps up. 766 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) 767 return -EINVAL; 768 */ 769 770 pos = (unsigned long)cam->framebuf; 771 while (size > 0) { 772 page = vmalloc_to_pfn((void *)pos); 773 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) 774 return -EAGAIN; 775 776 start += PAGE_SIZE; 777 pos += PAGE_SIZE; 778 if (size > PAGE_SIZE) 779 size -= PAGE_SIZE; 780 else 781 size = 0; 782 } 783 784 return 0; 785} 786 787static const struct v4l2_file_operations vicam_fops = { 788 .owner = THIS_MODULE, 789 .open = vicam_open, 790 .release = vicam_close, 791 .read = vicam_read, 792 .mmap = vicam_mmap, 793 .ioctl = vicam_ioctl, 794}; 795 796static struct video_device vicam_template = { 797 .name = "ViCam-based USB Camera", 798 .fops = &vicam_fops, 799 .release = video_device_release_empty, 800}; 801 802/* table of devices that work with this driver */ 803static struct usb_device_id vicam_table[] = { 804 {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)}, 805 {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)}, 806 {} /* Terminating entry */ 807}; 808 809MODULE_DEVICE_TABLE(usb, vicam_table); 810 811static struct usb_driver vicam_driver = { 812 .name = "vicam", 813 .probe = vicam_probe, 814 .disconnect = vicam_disconnect, 815 .id_table = vicam_table 816}; 817 818/** 819 * vicam_probe 820 * @intf: the interface 821 * @id: the device id 822 * 823 * Called by the usb core when a new device is connected that it thinks 824 * this driver might be interested in. 825 */ 826static int 827vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) 828{ 829 struct usb_device *dev = interface_to_usbdev(intf); 830 int bulkEndpoint = 0; 831 const struct usb_host_interface *interface; 832 const struct usb_endpoint_descriptor *endpoint; 833 struct vicam_camera *cam; 834 835 printk(KERN_INFO "ViCam based webcam connected\n"); 836 837 interface = intf->cur_altsetting; 838 839 DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n", 840 interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints)); 841 endpoint = &interface->endpoint[0].desc; 842 843 if (usb_endpoint_is_bulk_in(endpoint)) { 844 /* we found a bulk in endpoint */ 845 bulkEndpoint = endpoint->bEndpointAddress; 846 } else { 847 printk(KERN_ERR 848 "No bulk in endpoint was found ?! (this is bad)\n"); 849 } 850 851 if ((cam = 852 kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) { 853 printk(KERN_WARNING 854 "could not allocate kernel memory for vicam_camera struct\n"); 855 return -ENOMEM; 856 } 857 858 859 cam->shutter_speed = 15; 860 861 mutex_init(&cam->cam_lock); 862 863 memcpy(&cam->vdev, &vicam_template, sizeof(vicam_template)); 864 video_set_drvdata(&cam->vdev, cam); 865 866 cam->udev = dev; 867 cam->bulkEndpoint = bulkEndpoint; 868 869 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) { 870 kfree(cam); 871 printk(KERN_WARNING "video_register_device failed\n"); 872 return -EIO; 873 } 874 875 printk(KERN_INFO "ViCam webcam driver now controlling device %s\n", 876 video_device_node_name(&cam->vdev)); 877 878 usb_set_intfdata (intf, cam); 879 880 return 0; 881} 882 883static void 884vicam_disconnect(struct usb_interface *intf) 885{ 886 int open_count; 887 struct vicam_camera *cam = usb_get_intfdata (intf); 888 usb_set_intfdata (intf, NULL); 889 890 /* we must unregister the device before taking its 891 * cam_lock. This is because the video open call 892 * holds the same lock as video unregister. if we 893 * unregister inside of the cam_lock and open also 894 * uses the cam_lock, we get deadlock. 895 */ 896 897 video_unregister_device(&cam->vdev); 898 899 /* stop the camera from being used */ 900 901 mutex_lock(&cam->cam_lock); 902 903 /* mark the camera as gone */ 904 905 cam->udev = NULL; 906 907 /* the only thing left to do is synchronize with 908 * our close/release function on who should release 909 * the camera memory. if there are any users using the 910 * camera, it's their job. if there are no users, 911 * it's ours. 912 */ 913 914 open_count = cam->open_count; 915 916 mutex_unlock(&cam->cam_lock); 917 918 if (!open_count) { 919 kfree(cam); 920 } 921 922 printk(KERN_DEBUG "ViCam-based WebCam disconnected\n"); 923} 924 925/* 926 */ 927static int __init 928usb_vicam_init(void) 929{ 930 int retval; 931 DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); 932 retval = usb_register(&vicam_driver); 933 if (retval) 934 printk(KERN_WARNING "usb_register failed!\n"); 935 return retval; 936} 937 938static void __exit 939usb_vicam_exit(void) 940{ 941 DBG(KERN_INFO 942 "ViCam-based WebCam driver shutdown\n"); 943 944 usb_deregister(&vicam_driver); 945} 946 947module_init(usb_vicam_init); 948module_exit(usb_vicam_exit); 949 950MODULE_AUTHOR(DRIVER_AUTHOR); 951MODULE_DESCRIPTION(DRIVER_DESC); 952MODULE_LICENSE("GPL"); 953MODULE_FIRMWARE("vicam/firmware.fw"); 954