]> err.no Git - linux-2.6/blob - drivers/media/video/usbvideo/vicam.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[linux-2.6] / drivers / media / video / usbvideo / vicam.c
1 /*
2  * USB ViCam WebCam driver
3  * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
4  *                    Christopher L Cheney (ccheney@cheney.cx),
5  *                    Pavel Machek (pavel@suse.cz),
6  *                    John Tyner (jtyner@cs.ucr.edu),
7  *                    Monroe Williams (monroe@pobox.com)
8  *
9  * Supports 3COM HomeConnect PC Digital WebCam
10  * Supports Compro PS39U WebCam
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  * This source code is based heavily on the CPiA webcam driver which was
27  * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
28  *
29  * Portions of this code were also copied from usbvideo.c
30  *
31  * Special thanks to the whole team at Sourceforge for help making
32  * this driver become a reality.  Notably:
33  * Andy Armstrong who reverse engineered the color encoding and
34  * Pavel Machek and Chris Cheney who worked on reverse engineering the
35  *    camera controls and wrote the first generation driver.
36  */
37
38 #include <linux/kernel.h>
39 #include <linux/module.h>
40 #include <linux/init.h>
41 #include <linux/videodev.h>
42 #include <linux/usb.h>
43 #include <linux/vmalloc.h>
44 #include <linux/slab.h>
45 #include <linux/mutex.h>
46 #include "usbvideo.h"
47
48 // #define VICAM_DEBUG
49
50 #ifdef VICAM_DEBUG
51 #define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
52 #define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
53 #else
54 #define DBG(fmn,args...) do {} while(0)
55 #endif
56
57 #define DRIVER_AUTHOR           "Joe Burks, jburks@wavicle.org"
58 #define DRIVER_DESC             "ViCam WebCam Driver"
59
60 /* Define these values to match your device */
61 #define USB_VICAM_VENDOR_ID     0x04c1
62 #define USB_VICAM_PRODUCT_ID    0x009d
63 #define USB_COMPRO_VENDOR_ID    0x0602
64 #define USB_COMPRO_PRODUCT_ID   0x1001
65
66 #define VICAM_BYTES_PER_PIXEL   3
67 #define VICAM_MAX_READ_SIZE     (512*242+128)
68 #define VICAM_MAX_FRAME_SIZE    (VICAM_BYTES_PER_PIXEL*320*240)
69 #define VICAM_FRAMES            2
70
71 #define VICAM_HEADER_SIZE       64
72
73 #define clamp( x, l, h )        max_t( __typeof__( x ),         \
74                                        ( l ),                   \
75                                        min_t( __typeof__( x ),  \
76                                               ( h ),            \
77                                               ( x ) ) )
78
79 /* Not sure what all the bytes in these char
80  * arrays do, but they're necessary to make
81  * the camera work.
82  */
83
84 static unsigned char setup1[] = {
85         0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
86         0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
87         0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
88         0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
89         0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
90 };
91
92 static unsigned char setup2[] = {
93         0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
94         0x00, 0x00
95 };
96
97 static unsigned char setup3[] = {
98         0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
99 };
100
101 static unsigned char setup4[] = {
102         0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
103         0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
104         0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
105         0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
106         0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
107         0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
108         0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
109         0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
110         0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
111         0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
112         0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
113         0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
114         0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
115         0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
116         0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
117         0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
118         0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
119         0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
120         0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
121         0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
122         0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
123         0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
124         0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
125         0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
126         0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
127         0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
128         0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
129         0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
130         0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
131         0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
132         0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
133         0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
134         0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
135         0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
136         0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
137         0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
138         0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
139         0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
140         0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
141         0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
142         0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
143         0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
144         0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
145         0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
146         0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
147         0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
148         0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
149         0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
150         0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
151         0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
152         0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
153         0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
154         0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
155         0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
156         0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
157         0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
158         0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
159         0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
160         0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
161         0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
162         0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
163         0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
164         0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
165         0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
166         0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
167         0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
168         0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
169         0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
170         0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
171         0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
172         0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
173         0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
174         0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
175         0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
176         0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
177         0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
178         0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
179         0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
180         0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
181         0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
182         0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
183         0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
184         0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
185         0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
186         0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
187         0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
188         0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
189         0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
190         0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
191         0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
192         0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
193         0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
194         0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
195         0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
196         0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
197         0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
198         0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
199         0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
200         0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
201         0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
202         0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
203         0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
204         0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
205         0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
206         0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
207         0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
208         0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
209         0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
210         0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
211         0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
212         0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
213         0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
214         0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
215         0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
216         0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
217         0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
218         0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
219         0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
220         0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
221         0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
222         0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
223         0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
224         0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
225         0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
226         0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
227         0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
228         0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
229         0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
230         0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
231         0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
232         0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
233         0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
234         0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
235         0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
236         0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
237         0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
238         0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
239         0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
240         0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
241         0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
242         0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
243         0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
244         0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
245         0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
246         0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
247         0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
248         0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
249         0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
250         0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
251         0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
252         0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
253         0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
254         0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
255         0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
256         0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
257         0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
258         0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
259         0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
260         0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
261         0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
262         0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
263         0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
264         0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
265         0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
266         0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
267         0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
268         0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
269         0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
270         0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
271         0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
272         0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
273         0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
274         0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
275         0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
276         0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
277         0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
278         0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
279         0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
280         0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
281         0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
282         0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
283         0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
284         0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
285         0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
286         0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
287         0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
288         0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
289         0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
290         0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
291         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 };
314
315 static unsigned char setup5[] = {
316         0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
317         0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
318         0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
319         0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
320         0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
321         0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
322         0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
323         0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
324         0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
325         0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
326         0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
327         0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
328         0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
329         0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
330         0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
331         0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
332         0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
333         0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
334         0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
335         0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
336         0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
337         0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
338         0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
339         0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
340         0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
341         0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
342         0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
343         0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
344         0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
345         0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
346         0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
347         0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
348         0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
349         0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
350         0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
351         0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
352         0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
353         0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
354         0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
355 };
356
357 /* rvmalloc / rvfree copied from usbvideo.c
358  *
359  * Not sure why these are not yet non-statics which I can reference through
360  * usbvideo.h the same as it is in 2.4.20.  I bet this will get fixed sometime
361  * in the future.
362  *
363 */
364 static void *rvmalloc(unsigned long size)
365 {
366         void *mem;
367         unsigned long adr;
368
369         size = PAGE_ALIGN(size);
370         mem = vmalloc_32(size);
371         if (!mem)
372                 return NULL;
373
374         memset(mem, 0, size); /* Clear the ram out, no junk to the user */
375         adr = (unsigned long) mem;
376         while (size > 0) {
377                 SetPageReserved(vmalloc_to_page((void *)adr));
378                 adr += PAGE_SIZE;
379                 size -= PAGE_SIZE;
380         }
381
382         return mem;
383 }
384
385 static void rvfree(void *mem, unsigned long size)
386 {
387         unsigned long adr;
388
389         if (!mem)
390                 return;
391
392         adr = (unsigned long) mem;
393         while ((long) size > 0) {
394                 ClearPageReserved(vmalloc_to_page((void *)adr));
395                 adr += PAGE_SIZE;
396                 size -= PAGE_SIZE;
397         }
398         vfree(mem);
399 }
400
401 struct vicam_camera {
402         u16 shutter_speed;      // capture shutter speed
403         u16 gain;               // capture gain
404
405         u8 *raw_image;          // raw data captured from the camera
406         u8 *framebuf;           // processed data in RGB24 format
407         u8 *cntrlbuf;           // area used to send control msgs
408
409         struct video_device vdev;       // v4l video device
410         struct usb_device *udev;        // usb device
411
412         /* guard against simultaneous accesses to the camera */
413         struct mutex cam_lock;
414
415         int is_initialized;
416         u8 open_count;
417         u8 bulkEndpoint;
418         int needsDummyRead;
419 };
420
421 static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
422 static void vicam_disconnect(struct usb_interface *intf);
423 static void read_frame(struct vicam_camera *cam, int framenum);
424 static void vicam_decode_color(const u8 *, u8 *);
425
426 static int __send_control_msg(struct vicam_camera *cam,
427                               u8 request,
428                               u16 value,
429                               u16 index,
430                               unsigned char *cp,
431                               u16 size)
432 {
433         int status;
434
435         /* cp must be memory that has been allocated by kmalloc */
436
437         status = usb_control_msg(cam->udev,
438                                  usb_sndctrlpipe(cam->udev, 0),
439                                  request,
440                                  USB_DIR_OUT | USB_TYPE_VENDOR |
441                                  USB_RECIP_DEVICE, value, index,
442                                  cp, size, 1000);
443
444         status = min(status, 0);
445
446         if (status < 0) {
447                 printk(KERN_INFO "Failed sending control message, error %d.\n",
448                        status);
449         }
450
451         return status;
452 }
453
454 static int send_control_msg(struct vicam_camera *cam,
455                             u8 request,
456                             u16 value,
457                             u16 index,
458                             unsigned char *cp,
459                             u16 size)
460 {
461         int status = -ENODEV;
462         mutex_lock(&cam->cam_lock);
463         if (cam->udev) {
464                 status = __send_control_msg(cam, request, value,
465                                             index, cp, size);
466         }
467         mutex_unlock(&cam->cam_lock);
468         return status;
469 }
470 static int
471 initialize_camera(struct vicam_camera *cam)
472 {
473         const struct {
474                 u8 *data;
475                 u32 size;
476         } firmware[] = {
477                 { .data = setup1, .size = sizeof(setup1) },
478                 { .data = setup2, .size = sizeof(setup2) },
479                 { .data = setup3, .size = sizeof(setup3) },
480                 { .data = setup4, .size = sizeof(setup4) },
481                 { .data = setup5, .size = sizeof(setup5) },
482                 { .data = setup3, .size = sizeof(setup3) },
483                 { .data = NULL, .size = 0 }
484         };
485
486         int err, i;
487
488         for (i = 0, err = 0; firmware[i].data && !err; i++) {
489                 memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
490
491                 err = send_control_msg(cam, 0xff, 0, 0,
492                                        cam->cntrlbuf, firmware[i].size);
493         }
494
495         return err;
496 }
497
498 static int
499 set_camera_power(struct vicam_camera *cam, int state)
500 {
501         int status;
502
503         if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
504                 return status;
505
506         if (state) {
507                 send_control_msg(cam, 0x55, 1, 0, NULL, 0);
508         }
509
510         return 0;
511 }
512
513 static int
514 vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
515 {
516         void __user *user_arg = (void __user *)arg;
517         struct vicam_camera *cam = file->private_data;
518         int retval = 0;
519
520         if (!cam)
521                 return -ENODEV;
522
523         switch (ioctlnr) {
524                 /* query capabilities */
525         case VIDIOCGCAP:
526                 {
527                         struct video_capability b;
528
529                         DBG("VIDIOCGCAP\n");
530                         memset(&b, 0, sizeof(b));
531                         strcpy(b.name, "ViCam-based Camera");
532                         b.type = VID_TYPE_CAPTURE;
533                         b.channels = 1;
534                         b.audios = 0;
535                         b.maxwidth = 320;       /* VIDEOSIZE_CIF */
536                         b.maxheight = 240;
537                         b.minwidth = 320;       /* VIDEOSIZE_48_48 */
538                         b.minheight = 240;
539
540                         if (copy_to_user(user_arg, &b, sizeof(b)))
541                                 retval = -EFAULT;
542
543                         break;
544                 }
545                 /* get/set video source - we are a camera and nothing else */
546         case VIDIOCGCHAN:
547                 {
548                         struct video_channel v;
549
550                         DBG("VIDIOCGCHAN\n");
551                         if (copy_from_user(&v, user_arg, sizeof(v))) {
552                                 retval = -EFAULT;
553                                 break;
554                         }
555                         if (v.channel != 0) {
556                                 retval = -EINVAL;
557                                 break;
558                         }
559
560                         v.channel = 0;
561                         strcpy(v.name, "Camera");
562                         v.tuners = 0;
563                         v.flags = 0;
564                         v.type = VIDEO_TYPE_CAMERA;
565                         v.norm = 0;
566
567                         if (copy_to_user(user_arg, &v, sizeof(v)))
568                                 retval = -EFAULT;
569                         break;
570                 }
571
572         case VIDIOCSCHAN:
573                 {
574                         int v;
575
576                         if (copy_from_user(&v, user_arg, sizeof(v)))
577                                 retval = -EFAULT;
578                         DBG("VIDIOCSCHAN %d\n", v);
579
580                         if (retval == 0 && v != 0)
581                                 retval = -EINVAL;
582
583                         break;
584                 }
585
586                 /* image properties */
587         case VIDIOCGPICT:
588                 {
589                         struct video_picture vp;
590                         DBG("VIDIOCGPICT\n");
591                         memset(&vp, 0, sizeof (struct video_picture));
592                         vp.brightness = cam->gain << 8;
593                         vp.depth = 24;
594                         vp.palette = VIDEO_PALETTE_RGB24;
595                         if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
596                                 retval = -EFAULT;
597                         break;
598                 }
599
600         case VIDIOCSPICT:
601                 {
602                         struct video_picture vp;
603
604                         if (copy_from_user(&vp, user_arg, sizeof(vp))) {
605                                 retval = -EFAULT;
606                                 break;
607                         }
608
609                         DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
610                             vp.palette);
611
612                         cam->gain = vp.brightness >> 8;
613
614                         if (vp.depth != 24
615                             || vp.palette != VIDEO_PALETTE_RGB24)
616                                 retval = -EINVAL;
617
618                         break;
619                 }
620
621                 /* get/set capture window */
622         case VIDIOCGWIN:
623                 {
624                         struct video_window vw;
625                         vw.x = 0;
626                         vw.y = 0;
627                         vw.width = 320;
628                         vw.height = 240;
629                         vw.chromakey = 0;
630                         vw.flags = 0;
631                         vw.clips = NULL;
632                         vw.clipcount = 0;
633
634                         DBG("VIDIOCGWIN\n");
635
636                         if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
637                                 retval = -EFAULT;
638
639                         // I'm not sure what the deal with a capture window is, it is very poorly described
640                         // in the doc.  So I won't support it now.
641                         break;
642                 }
643
644         case VIDIOCSWIN:
645                 {
646
647                         struct video_window vw;
648
649                         if (copy_from_user(&vw, user_arg, sizeof(vw))) {
650                                 retval = -EFAULT;
651                                 break;
652                         }
653
654                         DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
655
656                         if ( vw.width != 320 || vw.height != 240 )
657                                 retval = -EFAULT;
658
659                         break;
660                 }
661
662                 /* mmap interface */
663         case VIDIOCGMBUF:
664                 {
665                         struct video_mbuf vm;
666                         int i;
667
668                         DBG("VIDIOCGMBUF\n");
669                         memset(&vm, 0, sizeof (vm));
670                         vm.size =
671                             VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
672                         vm.frames = VICAM_FRAMES;
673                         for (i = 0; i < VICAM_FRAMES; i++)
674                                 vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
675
676                         if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
677                                 retval = -EFAULT;
678
679                         break;
680                 }
681
682         case VIDIOCMCAPTURE:
683                 {
684                         struct video_mmap vm;
685                         // int video_size;
686
687                         if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
688                                 retval = -EFAULT;
689                                 break;
690                         }
691
692                         DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
693
694                         if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
695                                 retval = -EINVAL;
696
697                         // in theory right here we'd start the image capturing
698                         // (fill in a bulk urb and submit it asynchronously)
699                         //
700                         // Instead we're going to do a total hack job for now and
701                         // retrieve the frame in VIDIOCSYNC
702
703                         break;
704                 }
705
706         case VIDIOCSYNC:
707                 {
708                         int frame;
709
710                         if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
711                                 retval = -EFAULT;
712                                 break;
713                         }
714                         DBG("VIDIOCSYNC: %d\n", frame);
715
716                         read_frame(cam, frame);
717                         vicam_decode_color(cam->raw_image,
718                                            cam->framebuf +
719                                            frame * VICAM_MAX_FRAME_SIZE );
720
721                         break;
722                 }
723
724                 /* pointless to implement overlay with this camera */
725         case VIDIOCCAPTURE:
726         case VIDIOCGFBUF:
727         case VIDIOCSFBUF:
728         case VIDIOCKEY:
729                 retval = -EINVAL;
730                 break;
731
732                 /* tuner interface - we have none */
733         case VIDIOCGTUNER:
734         case VIDIOCSTUNER:
735         case VIDIOCGFREQ:
736         case VIDIOCSFREQ:
737                 retval = -EINVAL;
738                 break;
739
740                 /* audio interface - we have none */
741         case VIDIOCGAUDIO:
742         case VIDIOCSAUDIO:
743                 retval = -EINVAL;
744                 break;
745         default:
746                 retval = -ENOIOCTLCMD;
747                 break;
748         }
749
750         return retval;
751 }
752
753 static int
754 vicam_open(struct inode *inode, struct file *file)
755 {
756         struct video_device *dev = video_devdata(file);
757         struct vicam_camera *cam =
758             (struct vicam_camera *) dev->priv;
759         DBG("open\n");
760
761         if (!cam) {
762                 printk(KERN_ERR
763                        "vicam video_device improperly initialized");
764                 return -EINVAL;
765         }
766
767         /* the videodev_lock held above us protects us from
768          * simultaneous opens...for now. we probably shouldn't
769          * rely on this fact forever.
770          */
771
772         if (cam->open_count > 0) {
773                 printk(KERN_INFO
774                        "vicam_open called on already opened camera");
775                 return -EBUSY;
776         }
777
778         cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
779         if (!cam->raw_image) {
780                 return -ENOMEM;
781         }
782
783         cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
784         if (!cam->framebuf) {
785                 kfree(cam->raw_image);
786                 return -ENOMEM;
787         }
788
789         cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
790         if (!cam->cntrlbuf) {
791                 kfree(cam->raw_image);
792                 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
793                 return -ENOMEM;
794         }
795
796         // First upload firmware, then turn the camera on
797
798         if (!cam->is_initialized) {
799                 initialize_camera(cam);
800
801                 cam->is_initialized = 1;
802         }
803
804         set_camera_power(cam, 1);
805
806         cam->needsDummyRead = 1;
807         cam->open_count++;
808
809         file->private_data = cam;
810
811         return 0;
812 }
813
814 static int
815 vicam_close(struct inode *inode, struct file *file)
816 {
817         struct vicam_camera *cam = file->private_data;
818         int open_count;
819         struct usb_device *udev;
820
821         DBG("close\n");
822
823         /* it's not the end of the world if
824          * we fail to turn the camera off.
825          */
826
827         set_camera_power(cam, 0);
828
829         kfree(cam->raw_image);
830         rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
831         kfree(cam->cntrlbuf);
832
833         mutex_lock(&cam->cam_lock);
834
835         cam->open_count--;
836         open_count = cam->open_count;
837         udev = cam->udev;
838
839         mutex_unlock(&cam->cam_lock);
840
841         if (!open_count && !udev) {
842                 kfree(cam);
843         }
844
845         return 0;
846 }
847
848 static void vicam_decode_color(const u8 *data, u8 *rgb)
849 {
850         /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
851          * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
852          */
853
854         int i, prevY, nextY;
855
856         prevY = 512;
857         nextY = 512;
858
859         data += VICAM_HEADER_SIZE;
860
861         for( i = 0; i < 240; i++, data += 512 ) {
862                 const int y = ( i * 242 ) / 240;
863
864                 int j, prevX, nextX;
865                 int Y, Cr, Cb;
866
867                 if ( y == 242 - 1 ) {
868                         nextY = -512;
869                 }
870
871                 prevX = 1;
872                 nextX = 1;
873
874                 for ( j = 0; j < 320; j++, rgb += 3 ) {
875                         const int x = ( j * 512 ) / 320;
876                         const u8 * const src = &data[x];
877
878                         if ( x == 512 - 1 ) {
879                                 nextX = -1;
880                         }
881
882                         Cr = ( src[prevX] - src[0] ) +
883                                 ( src[nextX] - src[0] );
884                         Cr /= 2;
885
886                         Cb = ( src[prevY] - src[prevX + prevY] ) +
887                                 ( src[prevY] - src[nextX + prevY] ) +
888                                 ( src[nextY] - src[prevX + nextY] ) +
889                                 ( src[nextY] - src[nextX + nextY] );
890                         Cb /= 4;
891
892                         Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
893
894                         if ( i & 1 ) {
895                                 int Ct = Cr;
896                                 Cr = Cb;
897                                 Cb = Ct;
898                         }
899
900                         if ( ( x ^ i ) & 1 ) {
901                                 Cr = -Cr;
902                                 Cb = -Cb;
903                         }
904
905                         rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
906                                         500 ) / 900, 0, 255 );
907                         rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
908                                           ( 813 * Cr ) ) +
909                                           500 ) / 1000, 0, 255 );
910                         rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
911                                         500 ) / 1300, 0, 255 );
912
913                         prevX = -1;
914                 }
915
916                 prevY = -512;
917         }
918 }
919
920 static void
921 read_frame(struct vicam_camera *cam, int framenum)
922 {
923         unsigned char *request = cam->cntrlbuf;
924         int realShutter;
925         int n;
926         int actual_length;
927
928         if (cam->needsDummyRead) {
929                 cam->needsDummyRead = 0;
930                 read_frame(cam, framenum);
931         }
932
933         memset(request, 0, 16);
934         request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
935
936         request[1] = 0; // 512x242 capture
937
938         request[2] = 0x90;      // the function of these two bytes
939         request[3] = 0x07;      // is not yet understood
940
941         if (cam->shutter_speed > 60) {
942                 // Short exposure
943                 realShutter =
944                     ((-15631900 / cam->shutter_speed) + 260533) / 1000;
945                 request[4] = realShutter & 0xFF;
946                 request[5] = (realShutter >> 8) & 0xFF;
947                 request[6] = 0x03;
948                 request[7] = 0x01;
949         } else {
950                 // Long exposure
951                 realShutter = 15600 / cam->shutter_speed - 1;
952                 request[4] = 0;
953                 request[5] = 0;
954                 request[6] = realShutter & 0xFF;
955                 request[7] = realShutter >> 8;
956         }
957
958         // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
959         request[8] = 0;
960         // bytes 9-15 do not seem to affect exposure or image quality
961
962         mutex_lock(&cam->cam_lock);
963
964         if (!cam->udev) {
965                 goto done;
966         }
967
968         n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
969
970         if (n < 0) {
971                 printk(KERN_ERR
972                        " Problem sending frame capture control message");
973                 goto done;
974         }
975
976         n = usb_bulk_msg(cam->udev,
977                          usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
978                          cam->raw_image,
979                          512 * 242 + 128, &actual_length, 10000);
980
981         if (n < 0) {
982                 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
983                        n);
984         }
985
986  done:
987         mutex_unlock(&cam->cam_lock);
988 }
989
990 static ssize_t
991 vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
992 {
993         struct vicam_camera *cam = file->private_data;
994
995         DBG("read %d bytes.\n", (int) count);
996
997         if (*ppos >= VICAM_MAX_FRAME_SIZE) {
998                 *ppos = 0;
999                 return 0;
1000         }
1001
1002         if (*ppos == 0) {
1003                 read_frame(cam, 0);
1004                 vicam_decode_color(cam->raw_image,
1005                                    cam->framebuf +
1006                                    0 * VICAM_MAX_FRAME_SIZE);
1007         }
1008
1009         count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
1010
1011         if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
1012                 count = -EFAULT;
1013         } else {
1014                 *ppos += count;
1015         }
1016
1017         if (count == VICAM_MAX_FRAME_SIZE) {
1018                 *ppos = 0;
1019         }
1020
1021         return count;
1022 }
1023
1024
1025 static int
1026 vicam_mmap(struct file *file, struct vm_area_struct *vma)
1027 {
1028         // TODO: allocate the raw frame buffer if necessary
1029         unsigned long page, pos;
1030         unsigned long start = vma->vm_start;
1031         unsigned long size  = vma->vm_end-vma->vm_start;
1032         struct vicam_camera *cam = file->private_data;
1033
1034         if (!cam)
1035                 return -ENODEV;
1036
1037         DBG("vicam_mmap: %ld\n", size);
1038
1039         /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1040          * to the size the application requested for mmap and it was screwing apps up.
1041          if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1042          return -EINVAL;
1043          */
1044
1045         pos = (unsigned long)cam->framebuf;
1046         while (size > 0) {
1047                 page = vmalloc_to_pfn((void *)pos);
1048                 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1049                         return -EAGAIN;
1050
1051                 start += PAGE_SIZE;
1052                 pos += PAGE_SIZE;
1053                 if (size > PAGE_SIZE)
1054                         size -= PAGE_SIZE;
1055                 else
1056                         size = 0;
1057         }
1058
1059         return 0;
1060 }
1061
1062 static const struct file_operations vicam_fops = {
1063         .owner          = THIS_MODULE,
1064         .open           = vicam_open,
1065         .release        = vicam_close,
1066         .read           = vicam_read,
1067         .mmap           = vicam_mmap,
1068         .ioctl          = vicam_ioctl,
1069         .compat_ioctl   = v4l_compat_ioctl32,
1070         .llseek         = no_llseek,
1071 };
1072
1073 static struct video_device vicam_template = {
1074         .owner          = THIS_MODULE,
1075         .name           = "ViCam-based USB Camera",
1076         .type           = VID_TYPE_CAPTURE,
1077         .hardware       = VID_HARDWARE_VICAM,
1078         .fops           = &vicam_fops,
1079         .minor          = -1,
1080 };
1081
1082 /* table of devices that work with this driver */
1083 static struct usb_device_id vicam_table[] = {
1084         {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1085         {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
1086         {}                      /* Terminating entry */
1087 };
1088
1089 MODULE_DEVICE_TABLE(usb, vicam_table);
1090
1091 static struct usb_driver vicam_driver = {
1092         .name           = "vicam",
1093         .probe          = vicam_probe,
1094         .disconnect     = vicam_disconnect,
1095         .id_table       = vicam_table
1096 };
1097
1098 /**
1099  *      vicam_probe
1100  *      @intf: the interface
1101  *      @id: the device id
1102  *
1103  *      Called by the usb core when a new device is connected that it thinks
1104  *      this driver might be interested in.
1105  */
1106 static int
1107 vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
1108 {
1109         struct usb_device *dev = interface_to_usbdev(intf);
1110         int bulkEndpoint = 0;
1111         const struct usb_host_interface *interface;
1112         const struct usb_endpoint_descriptor *endpoint;
1113         struct vicam_camera *cam;
1114
1115         printk(KERN_INFO "ViCam based webcam connected\n");
1116
1117         interface = intf->cur_altsetting;
1118
1119         DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1120                interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
1121         endpoint = &interface->endpoint[0].desc;
1122
1123         if ((endpoint->bEndpointAddress & 0x80) &&
1124             ((endpoint->bmAttributes & 3) == 0x02)) {
1125                 /* we found a bulk in endpoint */
1126                 bulkEndpoint = endpoint->bEndpointAddress;
1127         } else {
1128                 printk(KERN_ERR
1129                        "No bulk in endpoint was found ?! (this is bad)\n");
1130         }
1131
1132         if ((cam =
1133              kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1134                 printk(KERN_WARNING
1135                        "could not allocate kernel memory for vicam_camera struct\n");
1136                 return -ENOMEM;
1137         }
1138
1139
1140         cam->shutter_speed = 15;
1141
1142         mutex_init(&cam->cam_lock);
1143
1144         memcpy(&cam->vdev, &vicam_template,
1145                sizeof (vicam_template));
1146         cam->vdev.priv = cam;   // sort of a reverse mapping for those functions that get vdev only
1147
1148         cam->udev = dev;
1149         cam->bulkEndpoint = bulkEndpoint;
1150
1151         if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1152                 kfree(cam);
1153                 printk(KERN_WARNING "video_register_device failed\n");
1154                 return -EIO;
1155         }
1156
1157         printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1158
1159         usb_set_intfdata (intf, cam);
1160
1161         return 0;
1162 }
1163
1164 static void
1165 vicam_disconnect(struct usb_interface *intf)
1166 {
1167         int open_count;
1168         struct vicam_camera *cam = usb_get_intfdata (intf);
1169         usb_set_intfdata (intf, NULL);
1170
1171         /* we must unregister the device before taking its
1172          * cam_lock. This is because the video open call
1173          * holds the same lock as video unregister. if we
1174          * unregister inside of the cam_lock and open also
1175          * uses the cam_lock, we get deadlock.
1176          */
1177
1178         video_unregister_device(&cam->vdev);
1179
1180         /* stop the camera from being used */
1181
1182         mutex_lock(&cam->cam_lock);
1183
1184         /* mark the camera as gone */
1185
1186         cam->udev = NULL;
1187
1188         /* the only thing left to do is synchronize with
1189          * our close/release function on who should release
1190          * the camera memory. if there are any users using the
1191          * camera, it's their job. if there are no users,
1192          * it's ours.
1193          */
1194
1195         open_count = cam->open_count;
1196
1197         mutex_unlock(&cam->cam_lock);
1198
1199         if (!open_count) {
1200                 kfree(cam);
1201         }
1202
1203         printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1204 }
1205
1206 /*
1207  */
1208 static int __init
1209 usb_vicam_init(void)
1210 {
1211         int retval;
1212         DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1213         retval = usb_register(&vicam_driver);
1214         if (retval)
1215                 printk(KERN_WARNING "usb_register failed!\n");
1216         return retval;
1217 }
1218
1219 static void __exit
1220 usb_vicam_exit(void)
1221 {
1222         DBG(KERN_INFO
1223                "ViCam-based WebCam driver shutdown\n");
1224
1225         usb_deregister(&vicam_driver);
1226 }
1227
1228 module_init(usb_vicam_init);
1229 module_exit(usb_vicam_exit);
1230
1231 MODULE_AUTHOR(DRIVER_AUTHOR);
1232 MODULE_DESCRIPTION(DRIVER_DESC);
1233 MODULE_LICENSE("GPL");