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