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