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 /* Not sure what all the bytes in these char
74 * arrays do, but they're necessary to make
78 static unsigned char setup1[] = {
79 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
80 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
81 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
82 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
83 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
86 static unsigned char setup2[] = {
87 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
91 static unsigned char setup3[] = {
92 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
95 static unsigned char setup4[] = {
96 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
97 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
98 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
99 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
100 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
101 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
102 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
103 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
104 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
105 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
106 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
107 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
108 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
109 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
110 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
111 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
112 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
113 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
114 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
115 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
116 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
117 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
118 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
119 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
120 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
121 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
122 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
123 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
124 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
125 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
126 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
127 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
128 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
129 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
130 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
131 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
132 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
133 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
134 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
135 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
136 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
137 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
138 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
139 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
140 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
141 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
142 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
143 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
144 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
145 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
146 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
147 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
148 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
149 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
150 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
151 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
152 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
153 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
154 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
155 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
156 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
157 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
158 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
159 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
160 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
161 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
162 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
163 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
164 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
165 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
166 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
167 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
168 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
169 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
170 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
171 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
172 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
173 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
174 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
175 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
176 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
177 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
178 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
179 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
180 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
181 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
182 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
183 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
184 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
185 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
186 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
187 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
188 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
189 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
190 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
191 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
192 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
193 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
194 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
195 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
196 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
197 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
198 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
199 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
200 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
201 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
202 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
203 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
204 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
205 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
206 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
207 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
208 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
209 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
210 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
211 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
212 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
213 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
214 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
215 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
216 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
217 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
218 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
219 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
220 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
221 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
222 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
223 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
224 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
225 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
226 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
227 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
228 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
229 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
230 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
231 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
232 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
233 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
234 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
235 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
236 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
237 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
238 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
239 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
240 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
241 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
242 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
243 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
244 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
245 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
246 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
247 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
248 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
249 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
250 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
251 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
252 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
253 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
254 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
255 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
256 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
257 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
258 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
259 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
260 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
261 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
262 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
263 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
264 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
265 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
266 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
267 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
268 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
269 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
270 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
271 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
272 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
273 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
274 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
275 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
276 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
277 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
278 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
279 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
280 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
281 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
282 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
283 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
284 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 static unsigned char setup5[] = {
310 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
311 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
312 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
313 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
314 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
315 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
316 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
317 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
318 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
319 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
320 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
321 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
322 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
323 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
324 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
325 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
326 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
327 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
328 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
329 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
330 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
331 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
332 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
333 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
334 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
335 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
336 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
337 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
338 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
339 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
340 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
341 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
342 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
343 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
344 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
345 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
346 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
347 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
348 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
351 /* rvmalloc / rvfree copied from usbvideo.c
353 * Not sure why these are not yet non-statics which I can reference through
354 * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime
358 static void *rvmalloc(unsigned long size)
363 size = PAGE_ALIGN(size);
364 mem = vmalloc_32(size);
368 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
369 adr = (unsigned long) mem;
371 SetPageReserved(vmalloc_to_page((void *)adr));
379 static void rvfree(void *mem, unsigned long size)
386 adr = (unsigned long) mem;
387 while ((long) size > 0) {
388 ClearPageReserved(vmalloc_to_page((void *)adr));
395 struct vicam_camera {
396 u16 shutter_speed; // capture shutter speed
397 u16 gain; // capture gain
399 u8 *raw_image; // raw data captured from the camera
400 u8 *framebuf; // processed data in RGB24 format
401 u8 *cntrlbuf; // area used to send control msgs
403 struct video_device vdev; // v4l video device
404 struct usb_device *udev; // usb device
406 /* guard against simultaneous accesses to the camera */
407 struct mutex cam_lock;
415 static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
416 static void vicam_disconnect(struct usb_interface *intf);
417 static void read_frame(struct vicam_camera *cam, int framenum);
418 static void vicam_decode_color(const u8 *, u8 *);
420 static int __send_control_msg(struct vicam_camera *cam,
429 /* cp must be memory that has been allocated by kmalloc */
431 status = usb_control_msg(cam->udev,
432 usb_sndctrlpipe(cam->udev, 0),
434 USB_DIR_OUT | USB_TYPE_VENDOR |
435 USB_RECIP_DEVICE, value, index,
438 status = min(status, 0);
441 printk(KERN_INFO "Failed sending control message, error %d.\n",
448 static int send_control_msg(struct vicam_camera *cam,
455 int status = -ENODEV;
456 mutex_lock(&cam->cam_lock);
458 status = __send_control_msg(cam, request, value,
461 mutex_unlock(&cam->cam_lock);
465 initialize_camera(struct vicam_camera *cam)
471 { .data = setup1, .size = sizeof(setup1) },
472 { .data = setup2, .size = sizeof(setup2) },
473 { .data = setup3, .size = sizeof(setup3) },
474 { .data = setup4, .size = sizeof(setup4) },
475 { .data = setup5, .size = sizeof(setup5) },
476 { .data = setup3, .size = sizeof(setup3) },
477 { .data = NULL, .size = 0 }
482 for (i = 0, err = 0; firmware[i].data && !err; i++) {
483 memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
485 err = send_control_msg(cam, 0xff, 0, 0,
486 cam->cntrlbuf, firmware[i].size);
493 set_camera_power(struct vicam_camera *cam, int state)
497 if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
501 send_control_msg(cam, 0x55, 1, 0, NULL, 0);
508 vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
510 void __user *user_arg = (void __user *)arg;
511 struct vicam_camera *cam = file->private_data;
518 /* query capabilities */
521 struct video_capability b;
524 memset(&b, 0, sizeof(b));
525 strcpy(b.name, "ViCam-based Camera");
526 b.type = VID_TYPE_CAPTURE;
529 b.maxwidth = 320; /* VIDEOSIZE_CIF */
531 b.minwidth = 320; /* VIDEOSIZE_48_48 */
534 if (copy_to_user(user_arg, &b, sizeof(b)))
539 /* get/set video source - we are a camera and nothing else */
542 struct video_channel v;
544 DBG("VIDIOCGCHAN\n");
545 if (copy_from_user(&v, user_arg, sizeof(v))) {
549 if (v.channel != 0) {
555 strcpy(v.name, "Camera");
558 v.type = VIDEO_TYPE_CAMERA;
561 if (copy_to_user(user_arg, &v, sizeof(v)))
570 if (copy_from_user(&v, user_arg, sizeof(v)))
572 DBG("VIDIOCSCHAN %d\n", v);
574 if (retval == 0 && v != 0)
580 /* image properties */
583 struct video_picture vp;
584 DBG("VIDIOCGPICT\n");
585 memset(&vp, 0, sizeof (struct video_picture));
586 vp.brightness = cam->gain << 8;
588 vp.palette = VIDEO_PALETTE_RGB24;
589 if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
596 struct video_picture vp;
598 if (copy_from_user(&vp, user_arg, sizeof(vp))) {
603 DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
606 cam->gain = vp.brightness >> 8;
609 || vp.palette != VIDEO_PALETTE_RGB24)
615 /* get/set capture window */
618 struct video_window vw;
630 if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
633 // I'm not sure what the deal with a capture window is, it is very poorly described
634 // in the doc. So I won't support it now.
641 struct video_window vw;
643 if (copy_from_user(&vw, user_arg, sizeof(vw))) {
648 DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
650 if ( vw.width != 320 || vw.height != 240 )
659 struct video_mbuf vm;
662 DBG("VIDIOCGMBUF\n");
663 memset(&vm, 0, sizeof (vm));
665 VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
666 vm.frames = VICAM_FRAMES;
667 for (i = 0; i < VICAM_FRAMES; i++)
668 vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
670 if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
678 struct video_mmap vm;
681 if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
686 DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
688 if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
691 // in theory right here we'd start the image capturing
692 // (fill in a bulk urb and submit it asynchronously)
694 // Instead we're going to do a total hack job for now and
695 // retrieve the frame in VIDIOCSYNC
704 if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
708 DBG("VIDIOCSYNC: %d\n", frame);
710 read_frame(cam, frame);
711 vicam_decode_color(cam->raw_image,
713 frame * VICAM_MAX_FRAME_SIZE );
718 /* pointless to implement overlay with this camera */
726 /* tuner interface - we have none */
734 /* audio interface - we have none */
740 retval = -ENOIOCTLCMD;
748 vicam_open(struct inode *inode, struct file *file)
750 struct video_device *dev = video_devdata(file);
751 struct vicam_camera *cam =
752 (struct vicam_camera *) dev->priv;
757 "vicam video_device improperly initialized");
761 /* the videodev_lock held above us protects us from
762 * simultaneous opens...for now. we probably shouldn't
763 * rely on this fact forever.
766 if (cam->open_count > 0) {
768 "vicam_open called on already opened camera");
772 cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
773 if (!cam->raw_image) {
777 cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
778 if (!cam->framebuf) {
779 kfree(cam->raw_image);
783 cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
784 if (!cam->cntrlbuf) {
785 kfree(cam->raw_image);
786 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
790 // First upload firmware, then turn the camera on
792 if (!cam->is_initialized) {
793 initialize_camera(cam);
795 cam->is_initialized = 1;
798 set_camera_power(cam, 1);
800 cam->needsDummyRead = 1;
803 file->private_data = cam;
809 vicam_close(struct inode *inode, struct file *file)
811 struct vicam_camera *cam = file->private_data;
813 struct usb_device *udev;
817 /* it's not the end of the world if
818 * we fail to turn the camera off.
821 set_camera_power(cam, 0);
823 kfree(cam->raw_image);
824 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
825 kfree(cam->cntrlbuf);
827 mutex_lock(&cam->cam_lock);
830 open_count = cam->open_count;
833 mutex_unlock(&cam->cam_lock);
835 if (!open_count && !udev) {
842 static void vicam_decode_color(const u8 *data, u8 *rgb)
844 /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
845 * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
853 data += VICAM_HEADER_SIZE;
855 for( i = 0; i < 240; i++, data += 512 ) {
856 const int y = ( i * 242 ) / 240;
861 if ( y == 242 - 1 ) {
868 for ( j = 0; j < 320; j++, rgb += 3 ) {
869 const int x = ( j * 512 ) / 320;
870 const u8 * const src = &data[x];
872 if ( x == 512 - 1 ) {
876 Cr = ( src[prevX] - src[0] ) +
877 ( src[nextX] - src[0] );
880 Cb = ( src[prevY] - src[prevX + prevY] ) +
881 ( src[prevY] - src[nextX + prevY] ) +
882 ( src[nextY] - src[prevX + nextY] ) +
883 ( src[nextY] - src[nextX + nextY] );
886 Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
894 if ( ( x ^ i ) & 1 ) {
899 rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
900 500 ) / 900, 0, 255 );
901 rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
903 500 ) / 1000, 0, 255 );
904 rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
905 500 ) / 1300, 0, 255 );
915 read_frame(struct vicam_camera *cam, int framenum)
917 unsigned char *request = cam->cntrlbuf;
922 if (cam->needsDummyRead) {
923 cam->needsDummyRead = 0;
924 read_frame(cam, framenum);
927 memset(request, 0, 16);
928 request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
930 request[1] = 0; // 512x242 capture
932 request[2] = 0x90; // the function of these two bytes
933 request[3] = 0x07; // is not yet understood
935 if (cam->shutter_speed > 60) {
938 ((-15631900 / cam->shutter_speed) + 260533) / 1000;
939 request[4] = realShutter & 0xFF;
940 request[5] = (realShutter >> 8) & 0xFF;
945 realShutter = 15600 / cam->shutter_speed - 1;
948 request[6] = realShutter & 0xFF;
949 request[7] = realShutter >> 8;
952 // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
954 // bytes 9-15 do not seem to affect exposure or image quality
956 mutex_lock(&cam->cam_lock);
962 n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
966 " Problem sending frame capture control message");
970 n = usb_bulk_msg(cam->udev,
971 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
973 512 * 242 + 128, &actual_length, 10000);
976 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
981 mutex_unlock(&cam->cam_lock);
985 vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
987 struct vicam_camera *cam = file->private_data;
989 DBG("read %d bytes.\n", (int) count);
991 if (*ppos >= VICAM_MAX_FRAME_SIZE) {
998 vicam_decode_color(cam->raw_image,
1000 0 * VICAM_MAX_FRAME_SIZE);
1003 count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
1005 if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
1011 if (count == VICAM_MAX_FRAME_SIZE) {
1020 vicam_mmap(struct file *file, struct vm_area_struct *vma)
1022 // TODO: allocate the raw frame buffer if necessary
1023 unsigned long page, pos;
1024 unsigned long start = vma->vm_start;
1025 unsigned long size = vma->vm_end-vma->vm_start;
1026 struct vicam_camera *cam = file->private_data;
1031 DBG("vicam_mmap: %ld\n", size);
1033 /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1034 * to the size the application requested for mmap and it was screwing apps up.
1035 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1039 pos = (unsigned long)cam->framebuf;
1041 page = vmalloc_to_pfn((void *)pos);
1042 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1047 if (size > PAGE_SIZE)
1056 static const struct file_operations vicam_fops = {
1057 .owner = THIS_MODULE,
1059 .release = vicam_close,
1062 .ioctl = vicam_ioctl,
1063 #ifdef CONFIG_COMPAT
1064 .compat_ioctl = v4l_compat_ioctl32,
1066 .llseek = no_llseek,
1069 static struct video_device vicam_template = {
1070 .owner = THIS_MODULE,
1071 .name = "ViCam-based USB Camera",
1072 .type = VID_TYPE_CAPTURE,
1073 .fops = &vicam_fops,
1077 /* table of devices that work with this driver */
1078 static struct usb_device_id vicam_table[] = {
1079 {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1080 {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
1081 {} /* Terminating entry */
1084 MODULE_DEVICE_TABLE(usb, vicam_table);
1086 static struct usb_driver vicam_driver = {
1088 .probe = vicam_probe,
1089 .disconnect = vicam_disconnect,
1090 .id_table = vicam_table
1095 * @intf: the interface
1096 * @id: the device id
1098 * Called by the usb core when a new device is connected that it thinks
1099 * this driver might be interested in.
1102 vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
1104 struct usb_device *dev = interface_to_usbdev(intf);
1105 int bulkEndpoint = 0;
1106 const struct usb_host_interface *interface;
1107 const struct usb_endpoint_descriptor *endpoint;
1108 struct vicam_camera *cam;
1110 printk(KERN_INFO "ViCam based webcam connected\n");
1112 interface = intf->cur_altsetting;
1114 DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1115 interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
1116 endpoint = &interface->endpoint[0].desc;
1118 if ((endpoint->bEndpointAddress & 0x80) &&
1119 ((endpoint->bmAttributes & 3) == 0x02)) {
1120 /* we found a bulk in endpoint */
1121 bulkEndpoint = endpoint->bEndpointAddress;
1124 "No bulk in endpoint was found ?! (this is bad)\n");
1128 kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1130 "could not allocate kernel memory for vicam_camera struct\n");
1135 cam->shutter_speed = 15;
1137 mutex_init(&cam->cam_lock);
1139 memcpy(&cam->vdev, &vicam_template,
1140 sizeof (vicam_template));
1141 cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only
1144 cam->bulkEndpoint = bulkEndpoint;
1146 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1148 printk(KERN_WARNING "video_register_device failed\n");
1152 printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1154 usb_set_intfdata (intf, cam);
1160 vicam_disconnect(struct usb_interface *intf)
1163 struct vicam_camera *cam = usb_get_intfdata (intf);
1164 usb_set_intfdata (intf, NULL);
1166 /* we must unregister the device before taking its
1167 * cam_lock. This is because the video open call
1168 * holds the same lock as video unregister. if we
1169 * unregister inside of the cam_lock and open also
1170 * uses the cam_lock, we get deadlock.
1173 video_unregister_device(&cam->vdev);
1175 /* stop the camera from being used */
1177 mutex_lock(&cam->cam_lock);
1179 /* mark the camera as gone */
1183 /* the only thing left to do is synchronize with
1184 * our close/release function on who should release
1185 * the camera memory. if there are any users using the
1186 * camera, it's their job. if there are no users,
1190 open_count = cam->open_count;
1192 mutex_unlock(&cam->cam_lock);
1198 printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1204 usb_vicam_init(void)
1207 DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1208 retval = usb_register(&vicam_driver);
1210 printk(KERN_WARNING "usb_register failed!\n");
1215 usb_vicam_exit(void)
1218 "ViCam-based WebCam driver shutdown\n");
1220 usb_deregister(&vicam_driver);
1223 module_init(usb_vicam_init);
1224 module_exit(usb_vicam_exit);
1226 MODULE_AUTHOR(DRIVER_AUTHOR);
1227 MODULE_DESCRIPTION(DRIVER_DESC);
1228 MODULE_LICENSE("GPL");