Merge branch 'config' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/bkl
[pandora-kernel.git] / drivers / staging / 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@ucw.cz),
6  *                    John Tyner (jtyner@cs.ucr.edu),
7  *                    Monroe Williams (monroe@pobox.com)
8  *
9  * Supports 3COM HomeConnect PC Digital WebCam
10  * Supports Compro PS39U WebCam
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  * This source code is based heavily on the CPiA webcam driver which was
27  * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
28  *
29  * Portions of this code were also copied from usbvideo.c
30  *
31  * Special thanks to the whole team at Sourceforge for help making
32  * this driver become a reality.  Notably:
33  * Andy Armstrong who reverse engineered the color encoding and
34  * Pavel Machek and Chris Cheney who worked on reverse engineering the
35  *    camera controls and wrote the first generation driver.
36  */
37
38 #include <linux/kernel.h>
39 #include <linux/module.h>
40 #include <linux/init.h>
41 #include "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 *uninitialized_var(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         status = send_control_msg(cam, 0x50, state, 0, NULL, 0);
223         if (status < 0)
224                 return status;
225
226         if (state)
227                 send_control_msg(cam, 0x55, 1, 0, NULL, 0);
228
229         return 0;
230 }
231
232 static long
233 vicam_ioctl(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         long 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",
412                             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         /* cam_lock/open_count protects us from simultaneous opens
487          * ... for now. we probably shouldn't rely on this fact forever.
488          */
489
490         mutex_lock(&cam->cam_lock);
491         if (cam->open_count > 0) {
492                 printk(KERN_INFO
493                        "vicam_open called on already opened camera");
494                 mutex_unlock(&cam->cam_lock);
495                 return -EBUSY;
496         }
497
498         cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
499         if (!cam->raw_image) {
500                 mutex_unlock(&cam->cam_lock);
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                 mutex_unlock(&cam->cam_lock);
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                 mutex_unlock(&cam->cam_lock);
516                 return -ENOMEM;
517         }
518
519         cam->needsDummyRead = 1;
520         cam->open_count++;
521
522         file->private_data = cam;
523         mutex_unlock(&cam->cam_lock);
524
525
526         /* First upload firmware, then turn the camera on */
527
528         if (!cam->is_initialized) {
529                 initialize_camera(cam);
530
531                 cam->is_initialized = 1;
532         }
533
534         set_camera_power(cam, 1);
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         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                 prevX = 1;
595                 nextX = 1;
596
597                 for (j = 0; j < 320; j++, rgb += 3) {
598                         const int x = (j * 512) / 320;
599                         const u8 * const src = &data[x];
600
601                         if (x == 512 - 1)
602                                 nextX = -1;
603
604                         Cr = (src[prevX] - src[0]) +
605                                 (src[nextX] - src[0]);
606                         Cr /= 2;
607
608                         Cb = (src[prevY] - src[prevX + prevY]) +
609                                 (src[prevY] - src[nextX + prevY]) +
610                                 (src[nextY] - src[prevX + nextY]) +
611                                 (src[nextY] - src[nextX + nextY]);
612                         Cb /= 4;
613
614                         Y = 1160 * (src[0] + (Cr / 2) - 16);
615
616                         if (i & 1) {
617                                 int Ct = Cr;
618                                 Cr = Cb;
619                                 Cb = Ct;
620                         }
621
622                         if ((x ^ i) & 1) {
623                                 Cr = -Cr;
624                                 Cb = -Cb;
625                         }
626
627                         rgb[0] = clamp(((Y + (2017 * Cb)) +
628                                         500) / 900, 0, 255);
629                         rgb[1] = clamp(((Y - (392 * Cb) -
630                                           (813 * Cr)) +
631                                           500) / 1000, 0, 255);
632                         rgb[2] = clamp(((Y + (1594 * Cr)) +
633                                         500) / 1300, 0, 255);
634
635                         prevX = -1;
636                 }
637
638                 prevY = -512;
639         }
640 }
641
642 static void
643 read_frame(struct vicam_camera *cam, int framenum)
644 {
645         unsigned char *request = cam->cntrlbuf;
646         int realShutter;
647         int n;
648         int actual_length;
649
650         if (cam->needsDummyRead) {
651                 cam->needsDummyRead = 0;
652                 read_frame(cam, framenum);
653         }
654
655         memset(request, 0, 16);
656         request[0] = cam->gain; /* 0 = 0% gain, FF = 100% gain */
657
658         request[1] = 0; /* 512x242 capture */
659
660         request[2] = 0x90;      /* the function of these two bytes */
661         request[3] = 0x07;      /* is not yet understood */
662
663         if (cam->shutter_speed > 60) {
664                 /* Short exposure */
665                 realShutter =
666                     ((-15631900 / cam->shutter_speed) + 260533) / 1000;
667                 request[4] = realShutter & 0xFF;
668                 request[5] = (realShutter >> 8) & 0xFF;
669                 request[6] = 0x03;
670                 request[7] = 0x01;
671         } else {
672                 /* Long exposure */
673                 realShutter = 15600 / cam->shutter_speed - 1;
674                 request[4] = 0;
675                 request[5] = 0;
676                 request[6] = realShutter & 0xFF;
677                 request[7] = realShutter >> 8;
678         }
679
680         /* Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0*/
681         request[8] = 0;
682         /* bytes 9-15 do not seem to affect exposure or image quality */
683
684         mutex_lock(&cam->cam_lock);
685
686         if (!cam->udev)
687                 goto done;
688
689         n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
690
691         if (n < 0) {
692                 printk(KERN_ERR
693                        " Problem sending frame capture control message");
694                 goto done;
695         }
696
697         n = usb_bulk_msg(cam->udev,
698                          usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
699                          cam->raw_image,
700                          512 * 242 + 128, &actual_length, 10000);
701
702         if (n < 0) {
703                 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
704                        n);
705         }
706
707  done:
708         mutex_unlock(&cam->cam_lock);
709 }
710
711 static ssize_t
712 vicam_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
713 {
714         struct vicam_camera *cam = file->private_data;
715
716         DBG("read %d bytes.\n", (int) count);
717
718         if (*ppos >= VICAM_MAX_FRAME_SIZE) {
719                 *ppos = 0;
720                 return 0;
721         }
722
723         if (*ppos == 0) {
724                 read_frame(cam, 0);
725                 vicam_decode_color(cam->raw_image,
726                                    cam->framebuf +
727                                    0 * VICAM_MAX_FRAME_SIZE);
728         }
729
730         count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
731
732         if (copy_to_user(buf, &cam->framebuf[*ppos], count))
733                 count = -EFAULT;
734         else
735                 *ppos += count;
736
737         if (count == VICAM_MAX_FRAME_SIZE)
738                 *ppos = 0;
739
740         return count;
741 }
742
743
744 static int
745 vicam_mmap(struct file *file, struct vm_area_struct *vma)
746 {
747         /* TODO: allocate the raw frame buffer if necessary */
748         unsigned long page, pos;
749         unsigned long start = vma->vm_start;
750         unsigned long size  = vma->vm_end-vma->vm_start;
751         struct vicam_camera *cam = file->private_data;
752
753         if (!cam)
754                 return -ENODEV;
755
756         DBG("vicam_mmap: %ld\n", size);
757
758         /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
759          * to the size the application requested for mmap and it was screwing apps up.
760          if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
761          return -EINVAL;
762          */
763
764         pos = (unsigned long)cam->framebuf;
765         while (size > 0) {
766                 page = vmalloc_to_pfn((void *)pos);
767                 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
768                         return -EAGAIN;
769
770                 start += PAGE_SIZE;
771                 pos += PAGE_SIZE;
772                 if (size > PAGE_SIZE)
773                         size -= PAGE_SIZE;
774                 else
775                         size = 0;
776         }
777
778         return 0;
779 }
780
781 static const struct v4l2_file_operations vicam_fops = {
782         .owner          = THIS_MODULE,
783         .open           = vicam_open,
784         .release        = vicam_close,
785         .read           = vicam_read,
786         .mmap           = vicam_mmap,
787         .ioctl          = vicam_ioctl,
788 };
789
790 static struct video_device vicam_template = {
791         .name           = "ViCam-based USB Camera",
792         .fops           = &vicam_fops,
793         .release        = video_device_release_empty,
794 };
795
796 /* table of devices that work with this driver */
797 static struct usb_device_id vicam_table[] = {
798         {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
799         {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
800         {}                      /* Terminating entry */
801 };
802
803 MODULE_DEVICE_TABLE(usb, vicam_table);
804
805 static struct usb_driver vicam_driver = {
806         .name           = "vicam",
807         .probe          = vicam_probe,
808         .disconnect     = vicam_disconnect,
809         .id_table       = vicam_table
810 };
811
812 /**
813  *      vicam_probe
814  *      @intf: the interface
815  *      @id: the device id
816  *
817  *      Called by the usb core when a new device is connected that it thinks
818  *      this driver might be interested in.
819  */
820 static int
821 vicam_probe(struct usb_interface *intf, const struct usb_device_id *id)
822 {
823         struct usb_device *dev = interface_to_usbdev(intf);
824         int bulkEndpoint = 0;
825         const struct usb_host_interface *interface;
826         const struct usb_endpoint_descriptor *endpoint;
827         struct vicam_camera *cam;
828
829         printk(KERN_INFO "ViCam based webcam connected\n");
830
831         interface = intf->cur_altsetting;
832
833         DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
834                interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
835         endpoint = &interface->endpoint[0].desc;
836
837         if (usb_endpoint_is_bulk_in(endpoint)) {
838                 /* we found a bulk in endpoint */
839                 bulkEndpoint = endpoint->bEndpointAddress;
840         } else {
841                 printk(KERN_ERR
842                        "No bulk in endpoint was found ?! (this is bad)\n");
843         }
844
845         cam = kzalloc(sizeof(struct vicam_camera), GFP_KERNEL);
846         if (cam == NULL) {
847                 printk(KERN_WARNING
848                        "could not allocate kernel memory for vicam_camera struct\n");
849                 return -ENOMEM;
850         }
851
852
853         cam->shutter_speed = 15;
854
855         mutex_init(&cam->cam_lock);
856
857         memcpy(&cam->vdev, &vicam_template, sizeof(vicam_template));
858         video_set_drvdata(&cam->vdev, cam);
859
860         cam->udev = dev;
861         cam->bulkEndpoint = bulkEndpoint;
862
863         if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) {
864                 kfree(cam);
865                 printk(KERN_WARNING "video_register_device failed\n");
866                 return -EIO;
867         }
868
869         printk(KERN_INFO "ViCam webcam driver now controlling device %s\n",
870                 video_device_node_name(&cam->vdev));
871
872         usb_set_intfdata(intf, cam);
873
874         return 0;
875 }
876
877 static void
878 vicam_disconnect(struct usb_interface *intf)
879 {
880         int open_count;
881         struct vicam_camera *cam = usb_get_intfdata(intf);
882         usb_set_intfdata(intf, NULL);
883
884         /* we must unregister the device before taking its
885          * cam_lock. This is because the video open call
886          * holds the same lock as video unregister. if we
887          * unregister inside of the cam_lock and open also
888          * uses the cam_lock, we get deadlock.
889          */
890
891         video_unregister_device(&cam->vdev);
892
893         /* stop the camera from being used */
894
895         mutex_lock(&cam->cam_lock);
896
897         /* mark the camera as gone */
898
899         cam->udev = NULL;
900
901         /* the only thing left to do is synchronize with
902          * our close/release function on who should release
903          * the camera memory. if there are any users using the
904          * camera, it's their job. if there are no users,
905          * it's ours.
906          */
907
908         open_count = cam->open_count;
909
910         mutex_unlock(&cam->cam_lock);
911
912         if (!open_count)
913                 kfree(cam);
914
915         printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
916 }
917
918 /*
919  */
920 static int __init
921 usb_vicam_init(void)
922 {
923         int retval;
924         DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
925         retval = usb_register(&vicam_driver);
926         if (retval)
927                 printk(KERN_WARNING "usb_register failed!\n");
928         return retval;
929 }
930
931 static void __exit
932 usb_vicam_exit(void)
933 {
934         DBG(KERN_INFO
935                "ViCam-based WebCam driver shutdown\n");
936
937         usb_deregister(&vicam_driver);
938 }
939
940 module_init(usb_vicam_init);
941 module_exit(usb_vicam_exit);
942
943 MODULE_AUTHOR(DRIVER_AUTHOR);
944 MODULE_DESCRIPTION(DRIVER_DESC);
945 MODULE_LICENSE("GPL");
946 MODULE_FIRMWARE("vicam/firmware.fw");