~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to drivers/staging/usbvideo/vicam.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno
  • Date: 2011-06-07 12:14:05 UTC
  • mfrom: (43.1.9 sid)
  • Revision ID: james.westby@ubuntu.com-20110607121405-i3h1rd7nrnd2b73h
Tags: 2.6.39-2
[ Ben Hutchings ]
* [x86] Enable BACKLIGHT_APPLE, replacing BACKLIGHT_MBP_NVIDIA
  (Closes: #627492)
* cgroups: Disable memory resource controller by default. Allow it
  to be enabled using kernel parameter 'cgroup_enable=memory'.
* rt2800usb: Enable support for more USB devices including
  Linksys WUSB600N (Closes: #596626) (this change was accidentally
  omitted from 2.6.39-1)
* [x86] Remove Celeron from list of processors supporting PAE. Most
  'Celeron M' models do not.
* Update debconf template translations:
  - Swedish (Martin Bagge) (Closes: #628932)
  - French (David Prévot) (Closes: #628191)
* aufs: Update for 2.6.39 (Closes: #627837)
* Add stable 2.6.39.1, including:
  - ext4: dont set PageUptodate in ext4_end_bio()
  - pata_cmd64x: fix boot crash on parisc (Closes: #622997, #622745)
  - ext3: Fix fs corruption when make_indexed_dir() fails
  - netfilter: nf_ct_sip: validate Content-Length in TCP SIP messages
  - sctp: fix race between sctp_bind_addr_free() and
    sctp_bind_addr_conflict()
  - sctp: fix memory leak of the ASCONF queue when free asoc
  - md/bitmap: fix saving of events_cleared and other state
  - cdc_acm: Fix oops when Droids MuIn LCD is connected
  - cx88: Fix conversion from BKL to fine-grained locks (Closes: #619827)
  - keys: Set cred->user_ns in key_replace_session_keyring (CVE-2011-2184)
  - tmpfs: fix race between truncate and writepage
  - nfs41: Correct offset for LAYOUTCOMMIT
  - xen/mmu: fix a race window causing leave_mm BUG()
  - ext4: fix possible use-after-free in ext4_remove_li_request()
  For the complete list of changes, see:
   http://www.kernel.org/pub/linux/kernel/v2.6/ChangeLog-2.6.39.1
* Bump ABI to 2
* netfilter: Enable IP_SET, IP_SET_BITMAP_IP, IP_SET_BITMAP_IPMAC,
  IP_SET_BITMAP_PORT, IP_SET_HASH_IP, IP_SET_HASH_IPPORT,
  IP_SET_HASH_IPPORTIP, IP_SET_HASH_IPPORTNET, IP_SET_HASH_NET,
  IP_SET_HASH_NETPORT, IP_SET_LIST_SET, NETFILTER_XT_SET as modules
  (Closes: #629401)

[ Aurelien Jarno ]
* [mipsel/loongson-2f] Disable_SCSI_LPFC to workaround GCC ICE.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
        if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
223
 
                return status;
224
 
 
225
 
        if (state) {
226
 
                send_control_msg(cam, 0x55, 1, 0, NULL, 0);
227
 
        }
228
 
 
229
 
        return 0;
230
 
}
231
 
 
232
 
static 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",vm.frame,vm.width,vm.height,vm.format);
412
 
 
413
 
                        if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
414
 
                                retval = -EINVAL;
415
 
 
416
 
                        // in theory right here we'd start the image capturing
417
 
                        // (fill in a bulk urb and submit it asynchronously)
418
 
                        //
419
 
                        // Instead we're going to do a total hack job for now and
420
 
                        // retrieve the frame in VIDIOCSYNC
421
 
 
422
 
                        break;
423
 
                }
424
 
 
425
 
        case VIDIOCSYNC:
426
 
                {
427
 
                        int frame;
428
 
 
429
 
                        if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
430
 
                                retval = -EFAULT;
431
 
                                break;
432
 
                        }
433
 
                        DBG("VIDIOCSYNC: %d\n", frame);
434
 
 
435
 
                        read_frame(cam, frame);
436
 
                        vicam_decode_color(cam->raw_image,
437
 
                                           cam->framebuf +
438
 
                                           frame * VICAM_MAX_FRAME_SIZE );
439
 
 
440
 
                        break;
441
 
                }
442
 
 
443
 
                /* pointless to implement overlay with this camera */
444
 
        case VIDIOCCAPTURE:
445
 
        case VIDIOCGFBUF:
446
 
        case VIDIOCSFBUF:
447
 
        case VIDIOCKEY:
448
 
                retval = -EINVAL;
449
 
                break;
450
 
 
451
 
                /* tuner interface - we have none */
452
 
        case VIDIOCGTUNER:
453
 
        case VIDIOCSTUNER:
454
 
        case VIDIOCGFREQ:
455
 
        case VIDIOCSFREQ:
456
 
                retval = -EINVAL;
457
 
                break;
458
 
 
459
 
                /* audio interface - we have none */
460
 
        case VIDIOCGAUDIO:
461
 
        case VIDIOCSAUDIO:
462
 
                retval = -EINVAL;
463
 
                break;
464
 
        default:
465
 
                retval = -ENOIOCTLCMD;
466
 
                break;
467
 
        }
468
 
 
469
 
        return retval;
470
 
}
471
 
 
472
 
static int
473
 
vicam_open(struct file *file)
474
 
{
475
 
        struct vicam_camera *cam = video_drvdata(file);
476
 
 
477
 
        DBG("open\n");
478
 
 
479
 
        if (!cam) {
480
 
                printk(KERN_ERR
481
 
                       "vicam video_device improperly initialized");
482
 
                return -EINVAL;
483
 
        }
484
 
 
485
 
        /* cam_lock/open_count protects us from simultaneous opens
486
 
         * ... for now. we probably shouldn't rely on this fact forever.
487
 
         */
488
 
 
489
 
        mutex_lock(&cam->cam_lock);
490
 
        if (cam->open_count > 0) {
491
 
                printk(KERN_INFO
492
 
                       "vicam_open called on already opened camera");
493
 
                mutex_unlock(&cam->cam_lock);
494
 
                return -EBUSY;
495
 
        }
496
 
 
497
 
        cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
498
 
        if (!cam->raw_image) {
499
 
                mutex_unlock(&cam->cam_lock);
500
 
                return -ENOMEM;
501
 
        }
502
 
 
503
 
        cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
504
 
        if (!cam->framebuf) {
505
 
                kfree(cam->raw_image);
506
 
                mutex_unlock(&cam->cam_lock);
507
 
                return -ENOMEM;
508
 
        }
509
 
 
510
 
        cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
511
 
        if (!cam->cntrlbuf) {
512
 
                kfree(cam->raw_image);
513
 
                rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
514
 
                mutex_unlock(&cam->cam_lock);
515
 
                return -ENOMEM;
516
 
        }
517
 
 
518
 
        cam->needsDummyRead = 1;
519
 
        cam->open_count++;
520
 
 
521
 
        file->private_data = cam;
522
 
        mutex_unlock(&cam->cam_lock);
523
 
 
524
 
 
525
 
        // First upload firmware, then turn the camera on
526
 
 
527
 
        if (!cam->is_initialized) {
528
 
                initialize_camera(cam);
529
 
 
530
 
                cam->is_initialized = 1;
531
 
        }
532
 
 
533
 
        set_camera_power(cam, 1);
534
 
 
535
 
        return 0;
536
 
}
537
 
 
538
 
static int
539
 
vicam_close(struct file *file)
540
 
{
541
 
        struct vicam_camera *cam = file->private_data;
542
 
        int open_count;
543
 
        struct usb_device *udev;
544
 
 
545
 
        DBG("close\n");
546
 
 
547
 
        /* it's not the end of the world if
548
 
         * we fail to turn the camera off.
549
 
         */
550
 
 
551
 
        set_camera_power(cam, 0);
552
 
 
553
 
        kfree(cam->raw_image);
554
 
        rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
555
 
        kfree(cam->cntrlbuf);
556
 
 
557
 
        mutex_lock(&cam->cam_lock);
558
 
 
559
 
        cam->open_count--;
560
 
        open_count = cam->open_count;
561
 
        udev = cam->udev;
562
 
 
563
 
        mutex_unlock(&cam->cam_lock);
564
 
 
565
 
        if (!open_count && !udev) {
566
 
                kfree(cam);
567
 
        }
568
 
 
569
 
        return 0;
570
 
}
571
 
 
572
 
static void vicam_decode_color(const u8 *data, u8 *rgb)
573
 
{
574
 
        /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
575
 
         * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
576
 
         */
577
 
 
578
 
        int i, prevY, nextY;
579
 
 
580
 
        prevY = 512;
581
 
        nextY = 512;
582
 
 
583
 
        data += VICAM_HEADER_SIZE;
584
 
 
585
 
        for( i = 0; i < 240; i++, data += 512 ) {
586
 
                const int y = ( i * 242 ) / 240;
587
 
 
588
 
                int j, prevX, nextX;
589
 
                int Y, Cr, Cb;
590
 
 
591
 
                if ( y == 242 - 1 ) {
592
 
                        nextY = -512;
593
 
                }
594
 
 
595
 
                prevX = 1;
596
 
                nextX = 1;
597
 
 
598
 
                for ( j = 0; j < 320; j++, rgb += 3 ) {
599
 
                        const int x = ( j * 512 ) / 320;
600
 
                        const u8 * const src = &data[x];
601
 
 
602
 
                        if ( x == 512 - 1 ) {
603
 
                                nextX = -1;
604
 
                        }
605
 
 
606
 
                        Cr = ( src[prevX] - src[0] ) +
607
 
                                ( src[nextX] - src[0] );
608
 
                        Cr /= 2;
609
 
 
610
 
                        Cb = ( src[prevY] - src[prevX + prevY] ) +
611
 
                                ( src[prevY] - src[nextX + prevY] ) +
612
 
                                ( src[nextY] - src[prevX + nextY] ) +
613
 
                                ( src[nextY] - src[nextX + nextY] );
614
 
                        Cb /= 4;
615
 
 
616
 
                        Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
617
 
 
618
 
                        if ( i & 1 ) {
619
 
                                int Ct = Cr;
620
 
                                Cr = Cb;
621
 
                                Cb = Ct;
622
 
                        }
623
 
 
624
 
                        if ( ( x ^ i ) & 1 ) {
625
 
                                Cr = -Cr;
626
 
                                Cb = -Cb;
627
 
                        }
628
 
 
629
 
                        rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
630
 
                                        500 ) / 900, 0, 255 );
631
 
                        rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
632
 
                                          ( 813 * Cr ) ) +
633
 
                                          500 ) / 1000, 0, 255 );
634
 
                        rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
635
 
                                        500 ) / 1300, 0, 255 );
636
 
 
637
 
                        prevX = -1;
638
 
                }
639
 
 
640
 
                prevY = -512;
641
 
        }
642
 
}
643
 
 
644
 
static void
645
 
read_frame(struct vicam_camera *cam, int framenum)
646
 
{
647
 
        unsigned char *request = cam->cntrlbuf;
648
 
        int realShutter;
649
 
        int n;
650
 
        int actual_length;
651
 
 
652
 
        if (cam->needsDummyRead) {
653
 
                cam->needsDummyRead = 0;
654
 
                read_frame(cam, framenum);
655
 
        }
656
 
 
657
 
        memset(request, 0, 16);
658
 
        request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
659
 
 
660
 
        request[1] = 0; // 512x242 capture
661
 
 
662
 
        request[2] = 0x90;      // the function of these two bytes
663
 
        request[3] = 0x07;      // is not yet understood
664
 
 
665
 
        if (cam->shutter_speed > 60) {
666
 
                // Short exposure
667
 
                realShutter =
668
 
                    ((-15631900 / cam->shutter_speed) + 260533) / 1000;
669
 
                request[4] = realShutter & 0xFF;
670
 
                request[5] = (realShutter >> 8) & 0xFF;
671
 
                request[6] = 0x03;
672
 
                request[7] = 0x01;
673
 
        } else {
674
 
                // Long exposure
675
 
                realShutter = 15600 / cam->shutter_speed - 1;
676
 
                request[4] = 0;
677
 
                request[5] = 0;
678
 
                request[6] = realShutter & 0xFF;
679
 
                request[7] = realShutter >> 8;
680
 
        }
681
 
 
682
 
        // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
683
 
        request[8] = 0;
684
 
        // bytes 9-15 do not seem to affect exposure or image quality
685
 
 
686
 
        mutex_lock(&cam->cam_lock);
687
 
 
688
 
        if (!cam->udev) {
689
 
                goto done;
690
 
        }
691
 
 
692
 
        n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
693
 
 
694
 
        if (n < 0) {
695
 
                printk(KERN_ERR
696
 
                       " Problem sending frame capture control message");
697
 
                goto done;
698
 
        }
699
 
 
700
 
        n = usb_bulk_msg(cam->udev,
701
 
                         usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
702
 
                         cam->raw_image,
703
 
                         512 * 242 + 128, &actual_length, 10000);
704
 
 
705
 
        if (n < 0) {
706
 
                printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
707
 
                       n);
708
 
        }
709
 
 
710
 
 done:
711
 
        mutex_unlock(&cam->cam_lock);
712
 
}
713
 
 
714
 
static ssize_t
715
 
vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
716
 
{
717
 
        struct vicam_camera *cam = file->private_data;
718
 
 
719
 
        DBG("read %d bytes.\n", (int) count);
720
 
 
721
 
        if (*ppos >= VICAM_MAX_FRAME_SIZE) {
722
 
                *ppos = 0;
723
 
                return 0;
724
 
        }
725
 
 
726
 
        if (*ppos == 0) {
727
 
                read_frame(cam, 0);
728
 
                vicam_decode_color(cam->raw_image,
729
 
                                   cam->framebuf +
730
 
                                   0 * VICAM_MAX_FRAME_SIZE);
731
 
        }
732
 
 
733
 
        count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
734
 
 
735
 
        if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
736
 
                count = -EFAULT;
737
 
        } else {
738
 
                *ppos += count;
739
 
        }
740
 
 
741
 
        if (count == VICAM_MAX_FRAME_SIZE) {
742
 
                *ppos = 0;
743
 
        }
744
 
 
745
 
        return count;
746
 
}
747
 
 
748
 
 
749
 
static int
750
 
vicam_mmap(struct file *file, struct vm_area_struct *vma)
751
 
{
752
 
        // TODO: allocate the raw frame buffer if necessary
753
 
        unsigned long page, pos;
754
 
        unsigned long start = vma->vm_start;
755
 
        unsigned long size  = vma->vm_end-vma->vm_start;
756
 
        struct vicam_camera *cam = file->private_data;
757
 
 
758
 
        if (!cam)
759
 
                return -ENODEV;
760
 
 
761
 
        DBG("vicam_mmap: %ld\n", size);
762
 
 
763
 
        /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
764
 
         * to the size the application requested for mmap and it was screwing apps up.
765
 
         if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
766
 
         return -EINVAL;
767
 
         */
768
 
 
769
 
        pos = (unsigned long)cam->framebuf;
770
 
        while (size > 0) {
771
 
                page = vmalloc_to_pfn((void *)pos);
772
 
                if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
773
 
                        return -EAGAIN;
774
 
 
775
 
                start += PAGE_SIZE;
776
 
                pos += PAGE_SIZE;
777
 
                if (size > PAGE_SIZE)
778
 
                        size -= PAGE_SIZE;
779
 
                else
780
 
                        size = 0;
781
 
        }
782
 
 
783
 
        return 0;
784
 
}
785
 
 
786
 
static const struct v4l2_file_operations vicam_fops = {
787
 
        .owner          = THIS_MODULE,
788
 
        .open           = vicam_open,
789
 
        .release        = vicam_close,
790
 
        .read           = vicam_read,
791
 
        .mmap           = vicam_mmap,
792
 
        .ioctl          = vicam_ioctl,
793
 
};
794
 
 
795
 
static struct video_device vicam_template = {
796
 
        .name           = "ViCam-based USB Camera",
797
 
        .fops           = &vicam_fops,
798
 
        .release        = video_device_release_empty,
799
 
};
800
 
 
801
 
/* table of devices that work with this driver */
802
 
static struct usb_device_id vicam_table[] = {
803
 
        {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
804
 
        {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
805
 
        {}                      /* Terminating entry */
806
 
};
807
 
 
808
 
MODULE_DEVICE_TABLE(usb, vicam_table);
809
 
 
810
 
static struct usb_driver vicam_driver = {
811
 
        .name           = "vicam",
812
 
        .probe          = vicam_probe,
813
 
        .disconnect     = vicam_disconnect,
814
 
        .id_table       = vicam_table
815
 
};
816
 
 
817
 
/**
818
 
 *      vicam_probe
819
 
 *      @intf: the interface
820
 
 *      @id: the device id
821
 
 *
822
 
 *      Called by the usb core when a new device is connected that it thinks
823
 
 *      this driver might be interested in.
824
 
 */
825
 
static int
826
 
vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
827
 
{
828
 
        struct usb_device *dev = interface_to_usbdev(intf);
829
 
        int bulkEndpoint = 0;
830
 
        const struct usb_host_interface *interface;
831
 
        const struct usb_endpoint_descriptor *endpoint;
832
 
        struct vicam_camera *cam;
833
 
 
834
 
        printk(KERN_INFO "ViCam based webcam connected\n");
835
 
 
836
 
        interface = intf->cur_altsetting;
837
 
 
838
 
        DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
839
 
               interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
840
 
        endpoint = &interface->endpoint[0].desc;
841
 
 
842
 
        if (usb_endpoint_is_bulk_in(endpoint)) {
843
 
                /* we found a bulk in endpoint */
844
 
                bulkEndpoint = endpoint->bEndpointAddress;
845
 
        } else {
846
 
                printk(KERN_ERR
847
 
                       "No bulk in endpoint was found ?! (this is bad)\n");
848
 
        }
849
 
 
850
 
        if ((cam =
851
 
             kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
852
 
                printk(KERN_WARNING
853
 
                       "could not allocate kernel memory for vicam_camera struct\n");
854
 
                return -ENOMEM;
855
 
        }
856
 
 
857
 
 
858
 
        cam->shutter_speed = 15;
859
 
 
860
 
        mutex_init(&cam->cam_lock);
861
 
 
862
 
        memcpy(&cam->vdev, &vicam_template, sizeof(vicam_template));
863
 
        video_set_drvdata(&cam->vdev, cam);
864
 
 
865
 
        cam->udev = dev;
866
 
        cam->bulkEndpoint = bulkEndpoint;
867
 
 
868
 
        if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) {
869
 
                kfree(cam);
870
 
                printk(KERN_WARNING "video_register_device failed\n");
871
 
                return -EIO;
872
 
        }
873
 
 
874
 
        printk(KERN_INFO "ViCam webcam driver now controlling device %s\n",
875
 
                video_device_node_name(&cam->vdev));
876
 
 
877
 
        usb_set_intfdata (intf, cam);
878
 
 
879
 
        return 0;
880
 
}
881
 
 
882
 
static void
883
 
vicam_disconnect(struct usb_interface *intf)
884
 
{
885
 
        int open_count;
886
 
        struct vicam_camera *cam = usb_get_intfdata (intf);
887
 
        usb_set_intfdata (intf, NULL);
888
 
 
889
 
        /* we must unregister the device before taking its
890
 
         * cam_lock. This is because the video open call
891
 
         * holds the same lock as video unregister. if we
892
 
         * unregister inside of the cam_lock and open also
893
 
         * uses the cam_lock, we get deadlock.
894
 
         */
895
 
 
896
 
        video_unregister_device(&cam->vdev);
897
 
 
898
 
        /* stop the camera from being used */
899
 
 
900
 
        mutex_lock(&cam->cam_lock);
901
 
 
902
 
        /* mark the camera as gone */
903
 
 
904
 
        cam->udev = NULL;
905
 
 
906
 
        /* the only thing left to do is synchronize with
907
 
         * our close/release function on who should release
908
 
         * the camera memory. if there are any users using the
909
 
         * camera, it's their job. if there are no users,
910
 
         * it's ours.
911
 
         */
912
 
 
913
 
        open_count = cam->open_count;
914
 
 
915
 
        mutex_unlock(&cam->cam_lock);
916
 
 
917
 
        if (!open_count) {
918
 
                kfree(cam);
919
 
        }
920
 
 
921
 
        printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
922
 
}
923
 
 
924
 
/*
925
 
 */
926
 
static int __init
927
 
usb_vicam_init(void)
928
 
{
929
 
        int retval;
930
 
        DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
931
 
        retval = usb_register(&vicam_driver);
932
 
        if (retval)
933
 
                printk(KERN_WARNING "usb_register failed!\n");
934
 
        return retval;
935
 
}
936
 
 
937
 
static void __exit
938
 
usb_vicam_exit(void)
939
 
{
940
 
        DBG(KERN_INFO
941
 
               "ViCam-based WebCam driver shutdown\n");
942
 
 
943
 
        usb_deregister(&vicam_driver);
944
 
}
945
 
 
946
 
module_init(usb_vicam_init);
947
 
module_exit(usb_vicam_exit);
948
 
 
949
 
MODULE_AUTHOR(DRIVER_AUTHOR);
950
 
MODULE_DESCRIPTION(DRIVER_DESC);
951
 
MODULE_LICENSE("GPL");
952
 
MODULE_FIRMWARE("vicam/firmware.fw");