]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/usb/media/vicam.c
8cfc47b831fb9bb29b06936c4c5f1ad24c873caa
[mv-sheeva.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         }
768
769         /* the videodev_lock held above us protects us from
770          * simultaneous opens...for now. we probably shouldn't
771          * rely on this fact forever.
772          */
773
774         if (cam->open_count > 0) {
775                 printk(KERN_INFO
776                        "vicam_open called on already opened camera");
777                 return -EBUSY;
778         }
779
780         cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
781         if (!cam->raw_image) {
782                 return -ENOMEM;
783         }
784
785         cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
786         if (!cam->framebuf) {
787                 kfree(cam->raw_image);
788                 return -ENOMEM;
789         }
790
791         cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
792         if (!cam->cntrlbuf) {
793                 kfree(cam->raw_image);
794                 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
795                 return -ENOMEM;
796         }
797
798         // First upload firmware, then turn the camera on
799
800         if (!cam->is_initialized) {
801                 initialize_camera(cam);
802
803                 cam->is_initialized = 1;
804         }
805
806         set_camera_power(cam, 1);
807
808         cam->needsDummyRead = 1;
809         cam->open_count++;
810
811         file->private_data = cam;       
812         
813         return 0;
814 }
815
816 static int 
817 vicam_close(struct inode *inode, struct file *file)
818 {
819         struct vicam_camera *cam = file->private_data;
820         int open_count;
821         struct usb_device *udev;
822
823         DBG("close\n");
824
825         /* it's not the end of the world if
826          * we fail to turn the camera off.
827          */
828
829         set_camera_power(cam, 0);
830
831         kfree(cam->raw_image);
832         rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
833         kfree(cam->cntrlbuf);
834
835         mutex_lock(&cam->cam_lock);
836
837         cam->open_count--;
838         open_count = cam->open_count;
839         udev = cam->udev;
840
841         mutex_unlock(&cam->cam_lock);
842
843         if (!open_count && !udev) {
844                 kfree(cam);
845         }
846
847         return 0;
848 }
849
850 static void vicam_decode_color(const u8 *data, u8 *rgb)
851 {
852         /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
853          * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
854          */
855
856         int i, prevY, nextY;
857
858         prevY = 512;
859         nextY = 512;
860
861         data += VICAM_HEADER_SIZE;
862
863         for( i = 0; i < 240; i++, data += 512 ) {
864                 const int y = ( i * 242 ) / 240;
865
866                 int j, prevX, nextX;
867                 int Y, Cr, Cb;
868
869                 if ( y == 242 - 1 ) {
870                         nextY = -512;
871                 }
872
873                 prevX = 1;
874                 nextX = 1;
875
876                 for ( j = 0; j < 320; j++, rgb += 3 ) {
877                         const int x = ( j * 512 ) / 320;
878                         const u8 * const src = &data[x];
879
880                         if ( x == 512 - 1 ) {
881                                 nextX = -1;
882                         }
883
884                         Cr = ( src[prevX] - src[0] ) +
885                                 ( src[nextX] - src[0] );
886                         Cr /= 2;
887
888                         Cb = ( src[prevY] - src[prevX + prevY] ) +
889                                 ( src[prevY] - src[nextX + prevY] ) +
890                                 ( src[nextY] - src[prevX + nextY] ) +
891                                 ( src[nextY] - src[nextX + nextY] );
892                         Cb /= 4;
893
894                         Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
895
896                         if ( i & 1 ) {
897                                 int Ct = Cr;
898                                 Cr = Cb;
899                                 Cb = Ct;
900                         }
901
902                         if ( ( x ^ i ) & 1 ) {
903                                 Cr = -Cr;
904                                 Cb = -Cb;
905                         }
906
907                         rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
908                                         500 ) / 900, 0, 255 );
909                         rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
910                                           ( 813 * Cr ) ) +
911                                           500 ) / 1000, 0, 255 );
912                         rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
913                                         500 ) / 1300, 0, 255 );
914
915                         prevX = -1;
916                 }
917
918                 prevY = -512;
919         }
920 }
921
922 static void
923 read_frame(struct vicam_camera *cam, int framenum)
924 {
925         unsigned char *request = cam->cntrlbuf;
926         int realShutter;
927         int n;
928         int actual_length;
929
930         if (cam->needsDummyRead) {
931                 cam->needsDummyRead = 0;
932                 read_frame(cam, framenum);
933         }
934
935         memset(request, 0, 16);
936         request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
937
938         request[1] = 0; // 512x242 capture
939
940         request[2] = 0x90;      // the function of these two bytes
941         request[3] = 0x07;      // is not yet understood
942
943         if (cam->shutter_speed > 60) {
944                 // Short exposure
945                 realShutter =
946                     ((-15631900 / cam->shutter_speed) + 260533) / 1000;
947                 request[4] = realShutter & 0xFF;
948                 request[5] = (realShutter >> 8) & 0xFF;
949                 request[6] = 0x03;
950                 request[7] = 0x01;
951         } else {
952                 // Long exposure
953                 realShutter = 15600 / cam->shutter_speed - 1;
954                 request[4] = 0;
955                 request[5] = 0;
956                 request[6] = realShutter & 0xFF;
957                 request[7] = realShutter >> 8;
958         }
959
960         // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
961         request[8] = 0;
962         // bytes 9-15 do not seem to affect exposure or image quality
963
964         mutex_lock(&cam->cam_lock);
965
966         if (!cam->udev) {
967                 goto done;
968         }
969
970         n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
971
972         if (n < 0) {
973                 printk(KERN_ERR
974                        " Problem sending frame capture control message");
975                 goto done;
976         }
977
978         n = usb_bulk_msg(cam->udev,
979                          usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
980                          cam->raw_image,
981                          512 * 242 + 128, &actual_length, 10000);
982
983         if (n < 0) {
984                 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
985                        n);
986         }
987
988  done:
989         mutex_unlock(&cam->cam_lock);
990 }
991
992 static ssize_t
993 vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
994 {
995         struct vicam_camera *cam = file->private_data;
996
997         DBG("read %d bytes.\n", (int) count);
998
999         if (*ppos >= VICAM_MAX_FRAME_SIZE) {
1000                 *ppos = 0;
1001                 return 0;
1002         }
1003
1004         if (*ppos == 0) {
1005                 read_frame(cam, 0);
1006                 vicam_decode_color(cam->raw_image,
1007                                    cam->framebuf +
1008                                    0 * VICAM_MAX_FRAME_SIZE);
1009         }
1010
1011         count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
1012
1013         if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
1014                 count = -EFAULT;
1015         } else {
1016                 *ppos += count;
1017         }
1018
1019         if (count == VICAM_MAX_FRAME_SIZE) {
1020                 *ppos = 0;
1021         }
1022
1023         return count;
1024 }
1025
1026
1027 static int
1028 vicam_mmap(struct file *file, struct vm_area_struct *vma)
1029 {
1030         // TODO: allocate the raw frame buffer if necessary
1031         unsigned long page, pos;
1032         unsigned long start = vma->vm_start;
1033         unsigned long size  = vma->vm_end-vma->vm_start;
1034         struct vicam_camera *cam = file->private_data;
1035
1036         if (!cam)
1037                 return -ENODEV;
1038
1039         DBG("vicam_mmap: %ld\n", size);
1040
1041         /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1042          * to the size the application requested for mmap and it was screwing apps up.
1043          if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1044          return -EINVAL;
1045          */
1046
1047         pos = (unsigned long)cam->framebuf;
1048         while (size > 0) {
1049                 page = vmalloc_to_pfn((void *)pos);
1050                 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1051                         return -EAGAIN;
1052
1053                 start += PAGE_SIZE;
1054                 pos += PAGE_SIZE;
1055                 if (size > PAGE_SIZE)
1056                         size -= PAGE_SIZE;
1057                 else
1058                         size = 0;
1059         }
1060
1061         return 0;
1062 }
1063
1064 #if defined(CONFIG_VIDEO_PROC_FS)
1065
1066 static struct proc_dir_entry *vicam_proc_root = NULL;
1067
1068 static int vicam_read_helper(char *page, char **start, off_t off,
1069                                 int count, int *eof, int value)
1070 {
1071         char *out = page;
1072         int len;
1073
1074         out += sprintf(out, "%d",value);
1075
1076         len = out - page;
1077         len -= off;
1078         if (len < count) {
1079                 *eof = 1;
1080                 if (len <= 0)
1081                         return 0;
1082         } else
1083                 len = count;
1084
1085         *start = page + off;
1086         return len;
1087 }
1088
1089 static int vicam_read_proc_shutter(char *page, char **start, off_t off,
1090                                 int count, int *eof, void *data)
1091 {
1092         return vicam_read_helper(page,start,off,count,eof,
1093                                 ((struct vicam_camera *)data)->shutter_speed);
1094 }
1095
1096 static int vicam_read_proc_gain(char *page, char **start, off_t off,
1097                                 int count, int *eof, void *data)
1098 {
1099         return vicam_read_helper(page,start,off,count,eof,
1100                                 ((struct vicam_camera *)data)->gain);
1101 }
1102
1103 static int
1104 vicam_write_proc_shutter(struct file *file, const char *buffer,
1105                          unsigned long count, void *data)
1106 {
1107         u16 stmp;
1108         char kbuf[8];
1109         struct vicam_camera *cam = (struct vicam_camera *) data;
1110
1111         if (count > 6)
1112                 return -EINVAL;
1113
1114         if (copy_from_user(kbuf, buffer, count))
1115                 return -EFAULT;
1116
1117         stmp = (u16) simple_strtoul(kbuf, NULL, 10);
1118         if (stmp < 4 || stmp > 32000)
1119                 return -EINVAL;
1120
1121         cam->shutter_speed = stmp;
1122
1123         return count;
1124 }
1125
1126 static int
1127 vicam_write_proc_gain(struct file *file, const char *buffer,
1128                       unsigned long count, void *data)
1129 {
1130         u16 gtmp;
1131         char kbuf[8];
1132
1133         struct vicam_camera *cam = (struct vicam_camera *) data;
1134
1135         if (count > 4)
1136                 return -EINVAL;
1137
1138         if (copy_from_user(kbuf, buffer, count))
1139                 return -EFAULT;
1140
1141         gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
1142         if (gtmp > 255)
1143                 return -EINVAL;
1144         cam->gain = gtmp;
1145
1146         return count;
1147 }
1148
1149 static void
1150 vicam_create_proc_root(void)
1151 {
1152         vicam_proc_root = proc_mkdir("video/vicam", NULL);
1153
1154         if (vicam_proc_root)
1155                 vicam_proc_root->owner = THIS_MODULE;
1156         else
1157                 printk(KERN_ERR
1158                        "could not create /proc entry for vicam!");
1159 }
1160
1161 static void
1162 vicam_destroy_proc_root(void)
1163 {
1164         if (vicam_proc_root)
1165                 remove_proc_entry("video/vicam", 0);
1166 }
1167
1168 static void
1169 vicam_create_proc_entry(struct vicam_camera *cam)
1170 {
1171         char name[64];
1172         struct proc_dir_entry *ent;
1173
1174         DBG(KERN_INFO "vicam: creating proc entry\n");
1175
1176         if (!vicam_proc_root || !cam) {
1177                 printk(KERN_INFO
1178                        "vicam: could not create proc entry, %s pointer is null.\n",
1179                        (!cam ? "camera" : "root"));
1180                 return;
1181         }
1182
1183         sprintf(name, "video%d", cam->vdev.minor);
1184
1185         cam->proc_dir = proc_mkdir(name, vicam_proc_root);
1186
1187         if ( !cam->proc_dir )
1188                 return; // FIXME: We should probably return an error here
1189         
1190         ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
1191                                 cam->proc_dir);
1192         if (ent) {
1193                 ent->data = cam;
1194                 ent->read_proc = vicam_read_proc_shutter;
1195                 ent->write_proc = vicam_write_proc_shutter;
1196                 ent->size = 64;
1197         }
1198
1199         ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
1200                                 cam->proc_dir);
1201         if (ent) {
1202                 ent->data = cam;
1203                 ent->read_proc = vicam_read_proc_gain;
1204                 ent->write_proc = vicam_write_proc_gain;
1205                 ent->size = 64;
1206         }
1207 }
1208
1209 static void
1210 vicam_destroy_proc_entry(void *ptr)
1211 {
1212         struct vicam_camera *cam = (struct vicam_camera *) ptr;
1213         char name[16];
1214
1215         if ( !cam->proc_dir )
1216                 return;
1217
1218         sprintf(name, "video%d", cam->vdev.minor);
1219         remove_proc_entry("shutter", cam->proc_dir);
1220         remove_proc_entry("gain", cam->proc_dir);
1221         remove_proc_entry(name,vicam_proc_root);
1222         cam->proc_dir = NULL;
1223
1224 }
1225
1226 #else
1227 static inline void vicam_create_proc_root(void) { }
1228 static inline void vicam_destroy_proc_root(void) { }
1229 static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
1230 static inline void vicam_destroy_proc_entry(void *ptr) { }
1231 #endif
1232
1233 static struct file_operations vicam_fops = {
1234         .owner          = THIS_MODULE,
1235         .open           = vicam_open,
1236         .release        = vicam_close,
1237         .read           = vicam_read,
1238         .mmap           = vicam_mmap,
1239         .ioctl          = vicam_ioctl,
1240         .compat_ioctl   = v4l_compat_ioctl32,
1241         .llseek         = no_llseek,
1242 };
1243
1244 static struct video_device vicam_template = {
1245         .owner          = THIS_MODULE,
1246         .name           = "ViCam-based USB Camera",
1247         .type           = VID_TYPE_CAPTURE,
1248         .hardware       = VID_HARDWARE_VICAM,
1249         .fops           = &vicam_fops,
1250         .minor          = -1,
1251 };
1252
1253 /* table of devices that work with this driver */
1254 static struct usb_device_id vicam_table[] = {
1255         {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1256         {}                      /* Terminating entry */
1257 };
1258
1259 MODULE_DEVICE_TABLE(usb, vicam_table);
1260
1261 static struct usb_driver vicam_driver = {
1262         .name           = "vicam",
1263         .probe          = vicam_probe,
1264         .disconnect     = vicam_disconnect,
1265         .id_table       = vicam_table
1266 };
1267
1268 /**
1269  *      vicam_probe
1270  *      @intf: the interface
1271  *      @id: the device id
1272  *
1273  *      Called by the usb core when a new device is connected that it thinks
1274  *      this driver might be interested in.
1275  */
1276 static int
1277 vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
1278 {
1279         struct usb_device *dev = interface_to_usbdev(intf);
1280         int bulkEndpoint = 0;
1281         const struct usb_host_interface *interface;
1282         const struct usb_endpoint_descriptor *endpoint;
1283         struct vicam_camera *cam;
1284         
1285         printk(KERN_INFO "ViCam based webcam connected\n");
1286
1287         interface = intf->cur_altsetting;
1288
1289         DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1290                interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
1291         endpoint = &interface->endpoint[0].desc;
1292
1293         if ((endpoint->bEndpointAddress & 0x80) &&
1294             ((endpoint->bmAttributes & 3) == 0x02)) {
1295                 /* we found a bulk in endpoint */
1296                 bulkEndpoint = endpoint->bEndpointAddress;
1297         } else {
1298                 printk(KERN_ERR
1299                        "No bulk in endpoint was found ?! (this is bad)\n");
1300         }
1301
1302         if ((cam =
1303              kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1304                 printk(KERN_WARNING
1305                        "could not allocate kernel memory for vicam_camera struct\n");
1306                 return -ENOMEM;
1307         }
1308
1309         memset(cam, 0, sizeof (struct vicam_camera));
1310
1311         cam->shutter_speed = 15;
1312
1313         mutex_init(&cam->cam_lock);
1314
1315         memcpy(&cam->vdev, &vicam_template,
1316                sizeof (vicam_template));
1317         cam->vdev.priv = cam;   // sort of a reverse mapping for those functions that get vdev only
1318
1319         cam->udev = dev;
1320         cam->bulkEndpoint = bulkEndpoint;
1321
1322         if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1323                 kfree(cam);
1324                 printk(KERN_WARNING "video_register_device failed\n");
1325                 return -EIO;
1326         }
1327
1328         vicam_create_proc_entry(cam);
1329
1330         printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1331
1332         usb_set_intfdata (intf, cam);
1333         
1334         return 0;
1335 }
1336
1337 static void
1338 vicam_disconnect(struct usb_interface *intf)
1339 {
1340         int open_count;
1341         struct vicam_camera *cam = usb_get_intfdata (intf);
1342         usb_set_intfdata (intf, NULL);
1343
1344         /* we must unregister the device before taking its
1345          * cam_lock. This is because the video open call
1346          * holds the same lock as video unregister. if we
1347          * unregister inside of the cam_lock and open also
1348          * uses the cam_lock, we get deadlock.
1349          */
1350
1351         video_unregister_device(&cam->vdev);
1352
1353         /* stop the camera from being used */
1354
1355         mutex_lock(&cam->cam_lock);
1356
1357         /* mark the camera as gone */
1358
1359         cam->udev = NULL;
1360
1361         vicam_destroy_proc_entry(cam);
1362
1363         /* the only thing left to do is synchronize with
1364          * our close/release function on who should release
1365          * the camera memory. if there are any users using the
1366          * camera, it's their job. if there are no users,
1367          * it's ours.
1368          */
1369
1370         open_count = cam->open_count;
1371
1372         mutex_unlock(&cam->cam_lock);
1373
1374         if (!open_count) {
1375                 kfree(cam);
1376         }
1377
1378         printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1379 }
1380
1381 /*
1382  */
1383 static int __init
1384 usb_vicam_init(void)
1385 {
1386         int retval;
1387         DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1388         vicam_create_proc_root();
1389         retval = usb_register(&vicam_driver);
1390         if (retval)
1391                 printk(KERN_WARNING "usb_register failed!\n");
1392         return retval;
1393 }
1394
1395 static void __exit
1396 usb_vicam_exit(void)
1397 {
1398         DBG(KERN_INFO
1399                "ViCam-based WebCam driver shutdown\n");
1400
1401         usb_deregister(&vicam_driver);
1402         vicam_destroy_proc_root();
1403 }
1404
1405 module_init(usb_vicam_init);
1406 module_exit(usb_vicam_exit);
1407
1408 MODULE_AUTHOR(DRIVER_AUTHOR);
1409 MODULE_DESCRIPTION(DRIVER_DESC);
1410 MODULE_LICENSE("GPL");