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