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