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