Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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");
955 
  This page was automatically generated by the LXR engine.