Merge branch 'topic/cleanup' into for-linus
[pandora-kernel.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/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 */
84 static 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
105 static 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
121 struct 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
141 static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
142 static void vicam_disconnect(struct usb_interface *intf);
143 static void read_frame(struct vicam_camera *cam, int framenum);
144 static void vicam_decode_color(const u8 *, u8 *);
145
146 static 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
174 static 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 }
190 static int
191 initialize_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
218 static int
219 set_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
233 static long
234 vicam_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
473 static int
474 vicam_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
539 static int
540 vicam_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
573 static 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
645 static void
646 read_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
715 static ssize_t
716 vicam_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
750 static int
751 vicam_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
787 static 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
796 static struct video_device vicam_template = {
797         .name           = "ViCam-based USB Camera",
798         .fops           = &vicam_fops,
799         .minor          = -1,
800         .release        = video_device_release_empty,
801 };
802
803 /* table of devices that work with this driver */
804 static struct usb_device_id vicam_table[] = {
805         {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
806         {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
807         {}                      /* Terminating entry */
808 };
809
810 MODULE_DEVICE_TABLE(usb, vicam_table);
811
812 static struct usb_driver vicam_driver = {
813         .name           = "vicam",
814         .probe          = vicam_probe,
815         .disconnect     = vicam_disconnect,
816         .id_table       = vicam_table
817 };
818
819 /**
820  *      vicam_probe
821  *      @intf: the interface
822  *      @id: the device id
823  *
824  *      Called by the usb core when a new device is connected that it thinks
825  *      this driver might be interested in.
826  */
827 static int
828 vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
829 {
830         struct usb_device *dev = interface_to_usbdev(intf);
831         int bulkEndpoint = 0;
832         const struct usb_host_interface *interface;
833         const struct usb_endpoint_descriptor *endpoint;
834         struct vicam_camera *cam;
835
836         printk(KERN_INFO "ViCam based webcam connected\n");
837
838         interface = intf->cur_altsetting;
839
840         DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
841                interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
842         endpoint = &interface->endpoint[0].desc;
843
844         if (usb_endpoint_is_bulk_in(endpoint)) {
845                 /* we found a bulk in endpoint */
846                 bulkEndpoint = endpoint->bEndpointAddress;
847         } else {
848                 printk(KERN_ERR
849                        "No bulk in endpoint was found ?! (this is bad)\n");
850         }
851
852         if ((cam =
853              kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
854                 printk(KERN_WARNING
855                        "could not allocate kernel memory for vicam_camera struct\n");
856                 return -ENOMEM;
857         }
858
859
860         cam->shutter_speed = 15;
861
862         mutex_init(&cam->cam_lock);
863
864         memcpy(&cam->vdev, &vicam_template, sizeof(vicam_template));
865         video_set_drvdata(&cam->vdev, cam);
866
867         cam->udev = dev;
868         cam->bulkEndpoint = bulkEndpoint;
869
870         if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) {
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",
877                         cam->vdev.num);
878
879         usb_set_intfdata (intf, cam);
880
881         return 0;
882 }
883
884 static void
885 vicam_disconnect(struct usb_interface *intf)
886 {
887         int open_count;
888         struct vicam_camera *cam = usb_get_intfdata (intf);
889         usb_set_intfdata (intf, NULL);
890
891         /* we must unregister the device before taking its
892          * cam_lock. This is because the video open call
893          * holds the same lock as video unregister. if we
894          * unregister inside of the cam_lock and open also
895          * uses the cam_lock, we get deadlock.
896          */
897
898         video_unregister_device(&cam->vdev);
899
900         /* stop the camera from being used */
901
902         mutex_lock(&cam->cam_lock);
903
904         /* mark the camera as gone */
905
906         cam->udev = NULL;
907
908         /* the only thing left to do is synchronize with
909          * our close/release function on who should release
910          * the camera memory. if there are any users using the
911          * camera, it's their job. if there are no users,
912          * it's ours.
913          */
914
915         open_count = cam->open_count;
916
917         mutex_unlock(&cam->cam_lock);
918
919         if (!open_count) {
920                 kfree(cam);
921         }
922
923         printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
924 }
925
926 /*
927  */
928 static int __init
929 usb_vicam_init(void)
930 {
931         int retval;
932         DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
933         retval = usb_register(&vicam_driver);
934         if (retval)
935                 printk(KERN_WARNING "usb_register failed!\n");
936         return retval;
937 }
938
939 static void __exit
940 usb_vicam_exit(void)
941 {
942         DBG(KERN_INFO
943                "ViCam-based WebCam driver shutdown\n");
944
945         usb_deregister(&vicam_driver);
946 }
947
948 module_init(usb_vicam_init);
949 module_exit(usb_vicam_exit);
950
951 MODULE_AUTHOR(DRIVER_AUTHOR);
952 MODULE_DESCRIPTION(DRIVER_DESC);
953 MODULE_LICENSE("GPL");
954 MODULE_FIRMWARE("vicam/firmware.fw");