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)
9 * Supports 3COM HomeConnect PC Digital WebCam
10 * Supports Compro PS39U WebCam
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * This source code is based heavily on the CPiA webcam driver which was
27 * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
29 * Portions of this code were also copied from usbvideo.c
31 * Special thanks to the whole team at Sourceforge for help making
32 * this driver become a reality. Notably:
33 * Andy Armstrong who reverse engineered the color encoding and
34 * Pavel Machek and Chris Cheney who worked on reverse engineering the
35 * camera controls and wrote the first generation driver.
38 #include <linux/kernel.h>
39 #include <linux/module.h>
40 #include <linux/init.h>
41 #include <linux/videodev.h>
42 #include <linux/usb.h>
43 #include <linux/vmalloc.h>
44 #include <linux/slab.h>
45 #include <linux/mutex.h>
48 // #define VICAM_DEBUG
51 #define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __func__, lineno, ##args)
52 #define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
54 #define DBG(fmn,args...) do {} while(0)
57 #define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org"
58 #define DRIVER_DESC "ViCam WebCam Driver"
60 /* Define these values to match your device */
61 #define USB_VICAM_VENDOR_ID 0x04c1
62 #define USB_VICAM_PRODUCT_ID 0x009d
63 #define USB_COMPRO_VENDOR_ID 0x0602
64 #define USB_COMPRO_PRODUCT_ID 0x1001
66 #define VICAM_BYTES_PER_PIXEL 3
67 #define VICAM_MAX_READ_SIZE (512*242+128)
68 #define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
69 #define VICAM_FRAMES 2
71 #define VICAM_HEADER_SIZE 64
73 #define clamp( x, l, h ) max_t( __typeof__( x ), \
75 min_t( __typeof__( x ), \
79 /* Not sure what all the bytes in these char
80 * arrays do, but they're necessary to make
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
92 static unsigned char setup2[] = {
93 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
97 static unsigned char setup3[] = {
98 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
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,
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
357 /* rvmalloc / rvfree copied from usbvideo.c
359 * Not sure why these are not yet non-statics which I can reference through
360 * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime
364 static void *rvmalloc(unsigned long size)
369 size = PAGE_ALIGN(size);
370 mem = vmalloc_32(size);
374 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
375 adr = (unsigned long) mem;
377 SetPageReserved(vmalloc_to_page((void *)adr));
385 static void rvfree(void *mem, unsigned long size)
392 adr = (unsigned long) mem;
393 while ((long) size > 0) {
394 ClearPageReserved(vmalloc_to_page((void *)adr));
401 struct vicam_camera {
402 u16 shutter_speed; // capture shutter speed
403 u16 gain; // capture gain
405 u8 *raw_image; // raw data captured from the camera
406 u8 *framebuf; // processed data in RGB24 format
407 u8 *cntrlbuf; // area used to send control msgs
409 struct video_device vdev; // v4l video device
410 struct usb_device *udev; // usb device
412 /* guard against simultaneous accesses to the camera */
413 struct mutex cam_lock;
421 static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
422 static void vicam_disconnect(struct usb_interface *intf);
423 static void read_frame(struct vicam_camera *cam, int framenum);
424 static void vicam_decode_color(const u8 *, u8 *);
426 static int __send_control_msg(struct vicam_camera *cam,
435 /* cp must be memory that has been allocated by kmalloc */
437 status = usb_control_msg(cam->udev,
438 usb_sndctrlpipe(cam->udev, 0),
440 USB_DIR_OUT | USB_TYPE_VENDOR |
441 USB_RECIP_DEVICE, value, index,
444 status = min(status, 0);
447 printk(KERN_INFO "Failed sending control message, error %d.\n",
454 static int send_control_msg(struct vicam_camera *cam,
461 int status = -ENODEV;
462 mutex_lock(&cam->cam_lock);
464 status = __send_control_msg(cam, request, value,
467 mutex_unlock(&cam->cam_lock);
471 initialize_camera(struct vicam_camera *cam)
477 { .data = setup1, .size = sizeof(setup1) },
478 { .data = setup2, .size = sizeof(setup2) },
479 { .data = setup3, .size = sizeof(setup3) },
480 { .data = setup4, .size = sizeof(setup4) },
481 { .data = setup5, .size = sizeof(setup5) },
482 { .data = setup3, .size = sizeof(setup3) },
483 { .data = NULL, .size = 0 }
488 for (i = 0, err = 0; firmware[i].data && !err; i++) {
489 memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
491 err = send_control_msg(cam, 0xff, 0, 0,
492 cam->cntrlbuf, firmware[i].size);
499 set_camera_power(struct vicam_camera *cam, int state)
503 if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
507 send_control_msg(cam, 0x55, 1, 0, NULL, 0);
514 vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
516 void __user *user_arg = (void __user *)arg;
517 struct vicam_camera *cam = file->private_data;
524 /* query capabilities */
527 struct video_capability b;
530 memset(&b, 0, sizeof(b));
531 strcpy(b.name, "ViCam-based Camera");
532 b.type = VID_TYPE_CAPTURE;
535 b.maxwidth = 320; /* VIDEOSIZE_CIF */
537 b.minwidth = 320; /* VIDEOSIZE_48_48 */
540 if (copy_to_user(user_arg, &b, sizeof(b)))
545 /* get/set video source - we are a camera and nothing else */
548 struct video_channel v;
550 DBG("VIDIOCGCHAN\n");
551 if (copy_from_user(&v, user_arg, sizeof(v))) {
555 if (v.channel != 0) {
561 strcpy(v.name, "Camera");
564 v.type = VIDEO_TYPE_CAMERA;
567 if (copy_to_user(user_arg, &v, sizeof(v)))
576 if (copy_from_user(&v, user_arg, sizeof(v)))
578 DBG("VIDIOCSCHAN %d\n", v);
580 if (retval == 0 && v != 0)
586 /* image properties */
589 struct video_picture vp;
590 DBG("VIDIOCGPICT\n");
591 memset(&vp, 0, sizeof (struct video_picture));
592 vp.brightness = cam->gain << 8;
594 vp.palette = VIDEO_PALETTE_RGB24;
595 if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
602 struct video_picture vp;
604 if (copy_from_user(&vp, user_arg, sizeof(vp))) {
609 DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
612 cam->gain = vp.brightness >> 8;
615 || vp.palette != VIDEO_PALETTE_RGB24)
621 /* get/set capture window */
624 struct video_window vw;
636 if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
639 // I'm not sure what the deal with a capture window is, it is very poorly described
640 // in the doc. So I won't support it now.
647 struct video_window vw;
649 if (copy_from_user(&vw, user_arg, sizeof(vw))) {
654 DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
656 if ( vw.width != 320 || vw.height != 240 )
665 struct video_mbuf vm;
668 DBG("VIDIOCGMBUF\n");
669 memset(&vm, 0, sizeof (vm));
671 VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
672 vm.frames = VICAM_FRAMES;
673 for (i = 0; i < VICAM_FRAMES; i++)
674 vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
676 if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
684 struct video_mmap vm;
687 if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
692 DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
694 if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
697 // in theory right here we'd start the image capturing
698 // (fill in a bulk urb and submit it asynchronously)
700 // Instead we're going to do a total hack job for now and
701 // retrieve the frame in VIDIOCSYNC
710 if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
714 DBG("VIDIOCSYNC: %d\n", frame);
716 read_frame(cam, frame);
717 vicam_decode_color(cam->raw_image,
719 frame * VICAM_MAX_FRAME_SIZE );
724 /* pointless to implement overlay with this camera */
732 /* tuner interface - we have none */
740 /* audio interface - we have none */
746 retval = -ENOIOCTLCMD;
754 vicam_open(struct inode *inode, struct file *file)
756 struct video_device *dev = video_devdata(file);
757 struct vicam_camera *cam =
758 (struct vicam_camera *) dev->priv;
763 "vicam video_device improperly initialized");
767 /* the videodev_lock held above us protects us from
768 * simultaneous opens...for now. we probably shouldn't
769 * rely on this fact forever.
772 if (cam->open_count > 0) {
774 "vicam_open called on already opened camera");
778 cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
779 if (!cam->raw_image) {
783 cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
784 if (!cam->framebuf) {
785 kfree(cam->raw_image);
789 cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
790 if (!cam->cntrlbuf) {
791 kfree(cam->raw_image);
792 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
796 // First upload firmware, then turn the camera on
798 if (!cam->is_initialized) {
799 initialize_camera(cam);
801 cam->is_initialized = 1;
804 set_camera_power(cam, 1);
806 cam->needsDummyRead = 1;
809 file->private_data = cam;
815 vicam_close(struct inode *inode, struct file *file)
817 struct vicam_camera *cam = file->private_data;
819 struct usb_device *udev;
823 /* it's not the end of the world if
824 * we fail to turn the camera off.
827 set_camera_power(cam, 0);
829 kfree(cam->raw_image);
830 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
831 kfree(cam->cntrlbuf);
833 mutex_lock(&cam->cam_lock);
836 open_count = cam->open_count;
839 mutex_unlock(&cam->cam_lock);
841 if (!open_count && !udev) {
848 static void vicam_decode_color(const u8 *data, u8 *rgb)
850 /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
851 * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
859 data += VICAM_HEADER_SIZE;
861 for( i = 0; i < 240; i++, data += 512 ) {
862 const int y = ( i * 242 ) / 240;
867 if ( y == 242 - 1 ) {
874 for ( j = 0; j < 320; j++, rgb += 3 ) {
875 const int x = ( j * 512 ) / 320;
876 const u8 * const src = &data[x];
878 if ( x == 512 - 1 ) {
882 Cr = ( src[prevX] - src[0] ) +
883 ( src[nextX] - src[0] );
886 Cb = ( src[prevY] - src[prevX + prevY] ) +
887 ( src[prevY] - src[nextX + prevY] ) +
888 ( src[nextY] - src[prevX + nextY] ) +
889 ( src[nextY] - src[nextX + nextY] );
892 Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
900 if ( ( x ^ i ) & 1 ) {
905 rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
906 500 ) / 900, 0, 255 );
907 rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
909 500 ) / 1000, 0, 255 );
910 rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
911 500 ) / 1300, 0, 255 );
921 read_frame(struct vicam_camera *cam, int framenum)
923 unsigned char *request = cam->cntrlbuf;
928 if (cam->needsDummyRead) {
929 cam->needsDummyRead = 0;
930 read_frame(cam, framenum);
933 memset(request, 0, 16);
934 request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
936 request[1] = 0; // 512x242 capture
938 request[2] = 0x90; // the function of these two bytes
939 request[3] = 0x07; // is not yet understood
941 if (cam->shutter_speed > 60) {
944 ((-15631900 / cam->shutter_speed) + 260533) / 1000;
945 request[4] = realShutter & 0xFF;
946 request[5] = (realShutter >> 8) & 0xFF;
951 realShutter = 15600 / cam->shutter_speed - 1;
954 request[6] = realShutter & 0xFF;
955 request[7] = realShutter >> 8;
958 // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
960 // bytes 9-15 do not seem to affect exposure or image quality
962 mutex_lock(&cam->cam_lock);
968 n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
972 " Problem sending frame capture control message");
976 n = usb_bulk_msg(cam->udev,
977 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
979 512 * 242 + 128, &actual_length, 10000);
982 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
987 mutex_unlock(&cam->cam_lock);
991 vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
993 struct vicam_camera *cam = file->private_data;
995 DBG("read %d bytes.\n", (int) count);
997 if (*ppos >= VICAM_MAX_FRAME_SIZE) {
1004 vicam_decode_color(cam->raw_image,
1006 0 * VICAM_MAX_FRAME_SIZE);
1009 count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
1011 if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
1017 if (count == VICAM_MAX_FRAME_SIZE) {
1026 vicam_mmap(struct file *file, struct vm_area_struct *vma)
1028 // TODO: allocate the raw frame buffer if necessary
1029 unsigned long page, pos;
1030 unsigned long start = vma->vm_start;
1031 unsigned long size = vma->vm_end-vma->vm_start;
1032 struct vicam_camera *cam = file->private_data;
1037 DBG("vicam_mmap: %ld\n", size);
1039 /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1040 * to the size the application requested for mmap and it was screwing apps up.
1041 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1045 pos = (unsigned long)cam->framebuf;
1047 page = vmalloc_to_pfn((void *)pos);
1048 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1053 if (size > PAGE_SIZE)
1062 static const struct file_operations vicam_fops = {
1063 .owner = THIS_MODULE,
1065 .release = vicam_close,
1068 .ioctl = vicam_ioctl,
1069 #ifdef CONFIG_COMPAT
1070 .compat_ioctl = v4l_compat_ioctl32,
1072 .llseek = no_llseek,
1075 static struct video_device vicam_template = {
1076 .owner = THIS_MODULE,
1077 .name = "ViCam-based USB Camera",
1078 .type = VID_TYPE_CAPTURE,
1079 .fops = &vicam_fops,
1083 /* table of devices that work with this driver */
1084 static struct usb_device_id vicam_table[] = {
1085 {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1086 {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
1087 {} /* Terminating entry */
1090 MODULE_DEVICE_TABLE(usb, vicam_table);
1092 static struct usb_driver vicam_driver = {
1094 .probe = vicam_probe,
1095 .disconnect = vicam_disconnect,
1096 .id_table = vicam_table
1101 * @intf: the interface
1102 * @id: the device id
1104 * Called by the usb core when a new device is connected that it thinks
1105 * this driver might be interested in.
1108 vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
1110 struct usb_device *dev = interface_to_usbdev(intf);
1111 int bulkEndpoint = 0;
1112 const struct usb_host_interface *interface;
1113 const struct usb_endpoint_descriptor *endpoint;
1114 struct vicam_camera *cam;
1116 printk(KERN_INFO "ViCam based webcam connected\n");
1118 interface = intf->cur_altsetting;
1120 DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1121 interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
1122 endpoint = &interface->endpoint[0].desc;
1124 if ((endpoint->bEndpointAddress & 0x80) &&
1125 ((endpoint->bmAttributes & 3) == 0x02)) {
1126 /* we found a bulk in endpoint */
1127 bulkEndpoint = endpoint->bEndpointAddress;
1130 "No bulk in endpoint was found ?! (this is bad)\n");
1134 kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1136 "could not allocate kernel memory for vicam_camera struct\n");
1141 cam->shutter_speed = 15;
1143 mutex_init(&cam->cam_lock);
1145 memcpy(&cam->vdev, &vicam_template,
1146 sizeof (vicam_template));
1147 cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only
1150 cam->bulkEndpoint = bulkEndpoint;
1152 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1154 printk(KERN_WARNING "video_register_device failed\n");
1158 printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1160 usb_set_intfdata (intf, cam);
1166 vicam_disconnect(struct usb_interface *intf)
1169 struct vicam_camera *cam = usb_get_intfdata (intf);
1170 usb_set_intfdata (intf, NULL);
1172 /* we must unregister the device before taking its
1173 * cam_lock. This is because the video open call
1174 * holds the same lock as video unregister. if we
1175 * unregister inside of the cam_lock and open also
1176 * uses the cam_lock, we get deadlock.
1179 video_unregister_device(&cam->vdev);
1181 /* stop the camera from being used */
1183 mutex_lock(&cam->cam_lock);
1185 /* mark the camera as gone */
1189 /* the only thing left to do is synchronize with
1190 * our close/release function on who should release
1191 * the camera memory. if there are any users using the
1192 * camera, it's their job. if there are no users,
1196 open_count = cam->open_count;
1198 mutex_unlock(&cam->cam_lock);
1204 printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1210 usb_vicam_init(void)
1213 DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1214 retval = usb_register(&vicam_driver);
1216 printk(KERN_WARNING "usb_register failed!\n");
1221 usb_vicam_exit(void)
1224 "ViCam-based WebCam driver shutdown\n");
1226 usb_deregister(&vicam_driver);
1229 module_init(usb_vicam_init);
1230 module_exit(usb_vicam_exit);
1232 MODULE_AUTHOR(DRIVER_AUTHOR);
1233 MODULE_DESCRIPTION(DRIVER_DESC);
1234 MODULE_LICENSE("GPL");