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