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/proc_fs.h>
46 #include <linux/mutex.h>
49 // #define VICAM_DEBUG
52 #define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
53 #define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
55 #define DBG(fmn,args...) do {} while(0)
58 #define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org"
59 #define DRIVER_DESC "ViCam WebCam Driver"
61 /* Define these values to match your device */
62 #define USB_VICAM_VENDOR_ID 0x04c1
63 #define USB_VICAM_PRODUCT_ID 0x009d
64 #define USB_COMPRO_VENDOR_ID 0x0602
65 #define USB_COMPRO_PRODUCT_ID 0x1001
67 #define VICAM_BYTES_PER_PIXEL 3
68 #define VICAM_MAX_READ_SIZE (512*242+128)
69 #define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
70 #define VICAM_FRAMES 2
72 #define VICAM_HEADER_SIZE 64
74 #define clamp( x, l, h ) max_t( __typeof__( x ), \
76 min_t( __typeof__( x ), \
80 /* Not sure what all the bytes in these char
81 * arrays do, but they're necessary to make
85 static unsigned char setup1[] = {
86 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
87 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
88 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
89 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
90 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
93 static unsigned char setup2[] = {
94 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
98 static unsigned char setup3[] = {
99 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
102 static unsigned char setup4[] = {
103 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
104 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
105 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
106 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
107 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
108 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
109 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
110 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
111 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
112 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
113 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
114 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
115 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
116 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
117 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
118 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
119 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
120 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
121 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
122 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
123 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
124 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
125 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
126 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
127 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
128 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
129 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
130 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
131 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
132 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
133 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
134 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
135 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
136 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
137 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
138 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
139 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
140 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
141 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
142 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
143 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
144 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
145 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
146 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
147 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
148 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
149 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
150 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
151 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
152 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
153 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
154 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
155 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
156 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
157 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
158 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
159 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
160 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
161 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
162 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
163 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
164 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
165 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
166 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
167 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
168 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
169 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
170 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
171 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
172 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
173 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
174 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
175 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
176 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
177 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
178 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
179 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
180 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
181 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
182 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
183 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
184 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
185 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
186 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
187 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
188 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
189 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
190 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
191 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
192 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
193 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
194 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
195 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
196 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
197 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
198 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
199 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
200 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
201 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
202 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
203 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
204 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
205 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
206 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
207 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
208 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
209 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
210 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
211 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
212 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
213 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
214 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
215 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
216 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
217 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
218 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
219 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
220 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
221 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
222 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
223 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
224 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
225 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
226 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
227 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
228 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
229 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
230 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
231 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
232 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
233 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
234 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
235 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
236 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
237 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
238 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
239 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
240 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
241 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
242 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
243 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
244 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
245 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
246 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
247 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
248 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
249 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
250 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
251 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
252 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
253 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
254 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
255 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
256 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
257 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
258 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
259 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
260 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
261 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
262 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
263 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
264 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
265 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
266 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
267 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
268 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
269 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
270 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
271 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
272 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
273 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
274 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
275 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
276 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
277 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
278 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
279 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
280 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
281 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
282 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
283 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
284 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
285 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
286 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
287 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
288 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
289 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
290 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
291 0x07, 0x05, 0x81, 0x02, 0x40, 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, 0x00, 0x00,
313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 static unsigned char setup5[] = {
317 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
318 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
319 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
320 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
321 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
322 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
323 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
324 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
325 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
326 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
327 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
328 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
329 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
330 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
331 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
332 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
333 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
334 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
335 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
336 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
337 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
338 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
339 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
340 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
341 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
342 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
343 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
344 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
345 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
346 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
347 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
348 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
349 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
350 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
351 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
352 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
353 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
354 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
355 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
358 /* rvmalloc / rvfree copied from usbvideo.c
360 * Not sure why these are not yet non-statics which I can reference through
361 * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime
365 static void *rvmalloc(unsigned long size)
370 size = PAGE_ALIGN(size);
371 mem = vmalloc_32(size);
375 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
376 adr = (unsigned long) mem;
378 SetPageReserved(vmalloc_to_page((void *)adr));
386 static void rvfree(void *mem, unsigned long size)
393 adr = (unsigned long) mem;
394 while ((long) size > 0) {
395 ClearPageReserved(vmalloc_to_page((void *)adr));
402 struct vicam_camera {
403 u16 shutter_speed; // capture shutter speed
404 u16 gain; // capture gain
406 u8 *raw_image; // raw data captured from the camera
407 u8 *framebuf; // processed data in RGB24 format
408 u8 *cntrlbuf; // area used to send control msgs
410 struct video_device vdev; // v4l video device
411 struct usb_device *udev; // usb device
413 /* guard against simultaneous accesses to the camera */
414 struct mutex cam_lock;
421 #if defined(CONFIG_VIDEO_PROC_FS)
422 struct proc_dir_entry *proc_dir;
427 static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
428 static void vicam_disconnect(struct usb_interface *intf);
429 static void read_frame(struct vicam_camera *cam, int framenum);
430 static void vicam_decode_color(const u8 *, u8 *);
432 static int __send_control_msg(struct vicam_camera *cam,
441 /* cp must be memory that has been allocated by kmalloc */
443 status = usb_control_msg(cam->udev,
444 usb_sndctrlpipe(cam->udev, 0),
446 USB_DIR_OUT | USB_TYPE_VENDOR |
447 USB_RECIP_DEVICE, value, index,
450 status = min(status, 0);
453 printk(KERN_INFO "Failed sending control message, error %d.\n",
460 static int send_control_msg(struct vicam_camera *cam,
467 int status = -ENODEV;
468 mutex_lock(&cam->cam_lock);
470 status = __send_control_msg(cam, request, value,
473 mutex_unlock(&cam->cam_lock);
477 initialize_camera(struct vicam_camera *cam)
483 { .data = setup1, .size = sizeof(setup1) },
484 { .data = setup2, .size = sizeof(setup2) },
485 { .data = setup3, .size = sizeof(setup3) },
486 { .data = setup4, .size = sizeof(setup4) },
487 { .data = setup5, .size = sizeof(setup5) },
488 { .data = setup3, .size = sizeof(setup3) },
489 { .data = NULL, .size = 0 }
494 for (i = 0, err = 0; firmware[i].data && !err; i++) {
495 memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
497 err = send_control_msg(cam, 0xff, 0, 0,
498 cam->cntrlbuf, firmware[i].size);
505 set_camera_power(struct vicam_camera *cam, int state)
509 if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
513 send_control_msg(cam, 0x55, 1, 0, NULL, 0);
520 vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
522 void __user *user_arg = (void __user *)arg;
523 struct vicam_camera *cam = file->private_data;
530 /* query capabilities */
533 struct video_capability b;
536 memset(&b, 0, sizeof(b));
537 strcpy(b.name, "ViCam-based Camera");
538 b.type = VID_TYPE_CAPTURE;
541 b.maxwidth = 320; /* VIDEOSIZE_CIF */
543 b.minwidth = 320; /* VIDEOSIZE_48_48 */
546 if (copy_to_user(user_arg, &b, sizeof(b)))
551 /* get/set video source - we are a camera and nothing else */
554 struct video_channel v;
556 DBG("VIDIOCGCHAN\n");
557 if (copy_from_user(&v, user_arg, sizeof(v))) {
561 if (v.channel != 0) {
567 strcpy(v.name, "Camera");
570 v.type = VIDEO_TYPE_CAMERA;
573 if (copy_to_user(user_arg, &v, sizeof(v)))
582 if (copy_from_user(&v, user_arg, sizeof(v)))
584 DBG("VIDIOCSCHAN %d\n", v);
586 if (retval == 0 && v != 0)
592 /* image properties */
595 struct video_picture vp;
596 DBG("VIDIOCGPICT\n");
597 memset(&vp, 0, sizeof (struct video_picture));
598 vp.brightness = cam->gain << 8;
600 vp.palette = VIDEO_PALETTE_RGB24;
601 if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
608 struct video_picture vp;
610 if (copy_from_user(&vp, user_arg, sizeof(vp))) {
615 DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
618 cam->gain = vp.brightness >> 8;
621 || vp.palette != VIDEO_PALETTE_RGB24)
627 /* get/set capture window */
630 struct video_window vw;
642 if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
645 // I'm not sure what the deal with a capture window is, it is very poorly described
646 // in the doc. So I won't support it now.
653 struct video_window vw;
655 if (copy_from_user(&vw, user_arg, sizeof(vw))) {
660 DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
662 if ( vw.width != 320 || vw.height != 240 )
671 struct video_mbuf vm;
674 DBG("VIDIOCGMBUF\n");
675 memset(&vm, 0, sizeof (vm));
677 VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
678 vm.frames = VICAM_FRAMES;
679 for (i = 0; i < VICAM_FRAMES; i++)
680 vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
682 if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
690 struct video_mmap vm;
693 if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
698 DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
700 if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
703 // in theory right here we'd start the image capturing
704 // (fill in a bulk urb and submit it asynchronously)
706 // Instead we're going to do a total hack job for now and
707 // retrieve the frame in VIDIOCSYNC
716 if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
720 DBG("VIDIOCSYNC: %d\n", frame);
722 read_frame(cam, frame);
723 vicam_decode_color(cam->raw_image,
725 frame * VICAM_MAX_FRAME_SIZE );
730 /* pointless to implement overlay with this camera */
738 /* tuner interface - we have none */
746 /* audio interface - we have none */
752 retval = -ENOIOCTLCMD;
760 vicam_open(struct inode *inode, struct file *file)
762 struct video_device *dev = video_devdata(file);
763 struct vicam_camera *cam =
764 (struct vicam_camera *) dev->priv;
769 "vicam video_device improperly initialized");
773 /* the videodev_lock held above us protects us from
774 * simultaneous opens...for now. we probably shouldn't
775 * rely on this fact forever.
778 if (cam->open_count > 0) {
780 "vicam_open called on already opened camera");
784 cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
785 if (!cam->raw_image) {
789 cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
790 if (!cam->framebuf) {
791 kfree(cam->raw_image);
795 cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
796 if (!cam->cntrlbuf) {
797 kfree(cam->raw_image);
798 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
802 // First upload firmware, then turn the camera on
804 if (!cam->is_initialized) {
805 initialize_camera(cam);
807 cam->is_initialized = 1;
810 set_camera_power(cam, 1);
812 cam->needsDummyRead = 1;
815 file->private_data = cam;
821 vicam_close(struct inode *inode, struct file *file)
823 struct vicam_camera *cam = file->private_data;
825 struct usb_device *udev;
829 /* it's not the end of the world if
830 * we fail to turn the camera off.
833 set_camera_power(cam, 0);
835 kfree(cam->raw_image);
836 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
837 kfree(cam->cntrlbuf);
839 mutex_lock(&cam->cam_lock);
842 open_count = cam->open_count;
845 mutex_unlock(&cam->cam_lock);
847 if (!open_count && !udev) {
854 static void vicam_decode_color(const u8 *data, u8 *rgb)
856 /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
857 * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
865 data += VICAM_HEADER_SIZE;
867 for( i = 0; i < 240; i++, data += 512 ) {
868 const int y = ( i * 242 ) / 240;
873 if ( y == 242 - 1 ) {
880 for ( j = 0; j < 320; j++, rgb += 3 ) {
881 const int x = ( j * 512 ) / 320;
882 const u8 * const src = &data[x];
884 if ( x == 512 - 1 ) {
888 Cr = ( src[prevX] - src[0] ) +
889 ( src[nextX] - src[0] );
892 Cb = ( src[prevY] - src[prevX + prevY] ) +
893 ( src[prevY] - src[nextX + prevY] ) +
894 ( src[nextY] - src[prevX + nextY] ) +
895 ( src[nextY] - src[nextX + nextY] );
898 Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
906 if ( ( x ^ i ) & 1 ) {
911 rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
912 500 ) / 900, 0, 255 );
913 rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
915 500 ) / 1000, 0, 255 );
916 rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
917 500 ) / 1300, 0, 255 );
927 read_frame(struct vicam_camera *cam, int framenum)
929 unsigned char *request = cam->cntrlbuf;
934 if (cam->needsDummyRead) {
935 cam->needsDummyRead = 0;
936 read_frame(cam, framenum);
939 memset(request, 0, 16);
940 request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
942 request[1] = 0; // 512x242 capture
944 request[2] = 0x90; // the function of these two bytes
945 request[3] = 0x07; // is not yet understood
947 if (cam->shutter_speed > 60) {
950 ((-15631900 / cam->shutter_speed) + 260533) / 1000;
951 request[4] = realShutter & 0xFF;
952 request[5] = (realShutter >> 8) & 0xFF;
957 realShutter = 15600 / cam->shutter_speed - 1;
960 request[6] = realShutter & 0xFF;
961 request[7] = realShutter >> 8;
964 // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
966 // bytes 9-15 do not seem to affect exposure or image quality
968 mutex_lock(&cam->cam_lock);
974 n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
978 " Problem sending frame capture control message");
982 n = usb_bulk_msg(cam->udev,
983 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
985 512 * 242 + 128, &actual_length, 10000);
988 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
993 mutex_unlock(&cam->cam_lock);
997 vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
999 struct vicam_camera *cam = file->private_data;
1001 DBG("read %d bytes.\n", (int) count);
1003 if (*ppos >= VICAM_MAX_FRAME_SIZE) {
1010 vicam_decode_color(cam->raw_image,
1012 0 * VICAM_MAX_FRAME_SIZE);
1015 count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
1017 if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
1023 if (count == VICAM_MAX_FRAME_SIZE) {
1032 vicam_mmap(struct file *file, struct vm_area_struct *vma)
1034 // TODO: allocate the raw frame buffer if necessary
1035 unsigned long page, pos;
1036 unsigned long start = vma->vm_start;
1037 unsigned long size = vma->vm_end-vma->vm_start;
1038 struct vicam_camera *cam = file->private_data;
1043 DBG("vicam_mmap: %ld\n", size);
1045 /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1046 * to the size the application requested for mmap and it was screwing apps up.
1047 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1051 pos = (unsigned long)cam->framebuf;
1053 page = vmalloc_to_pfn((void *)pos);
1054 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1059 if (size > PAGE_SIZE)
1068 #if defined(CONFIG_VIDEO_PROC_FS)
1070 static struct proc_dir_entry *vicam_proc_root = NULL;
1072 static int vicam_read_helper(char *page, char **start, off_t off,
1073 int count, int *eof, int value)
1078 out += sprintf(out, "%d",value);
1089 *start = page + off;
1093 static int vicam_read_proc_shutter(char *page, char **start, off_t off,
1094 int count, int *eof, void *data)
1096 return vicam_read_helper(page,start,off,count,eof,
1097 ((struct vicam_camera *)data)->shutter_speed);
1100 static int vicam_read_proc_gain(char *page, char **start, off_t off,
1101 int count, int *eof, void *data)
1103 return vicam_read_helper(page,start,off,count,eof,
1104 ((struct vicam_camera *)data)->gain);
1108 vicam_write_proc_shutter(struct file *file, const char *buffer,
1109 unsigned long count, void *data)
1113 struct vicam_camera *cam = (struct vicam_camera *) data;
1118 if (copy_from_user(kbuf, buffer, count))
1121 stmp = (u16) simple_strtoul(kbuf, NULL, 10);
1122 if (stmp < 4 || stmp > 32000)
1125 cam->shutter_speed = stmp;
1131 vicam_write_proc_gain(struct file *file, const char *buffer,
1132 unsigned long count, void *data)
1137 struct vicam_camera *cam = (struct vicam_camera *) data;
1142 if (copy_from_user(kbuf, buffer, count))
1145 gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
1154 vicam_create_proc_root(void)
1156 vicam_proc_root = proc_mkdir("video/vicam", NULL);
1158 if (vicam_proc_root)
1159 vicam_proc_root->owner = THIS_MODULE;
1162 "could not create /proc entry for vicam!");
1166 vicam_destroy_proc_root(void)
1168 if (vicam_proc_root)
1169 remove_proc_entry("video/vicam", 0);
1173 vicam_create_proc_entry(struct vicam_camera *cam)
1176 struct proc_dir_entry *ent;
1178 DBG(KERN_INFO "vicam: creating proc entry\n");
1180 if (!vicam_proc_root || !cam) {
1182 "vicam: could not create proc entry, %s pointer is null.\n",
1183 (!cam ? "camera" : "root"));
1187 sprintf(name, "video%d", cam->vdev.minor);
1189 cam->proc_dir = proc_mkdir(name, vicam_proc_root);
1191 if ( !cam->proc_dir )
1192 return; // FIXME: We should probably return an error here
1194 ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
1198 ent->read_proc = vicam_read_proc_shutter;
1199 ent->write_proc = vicam_write_proc_shutter;
1203 ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
1207 ent->read_proc = vicam_read_proc_gain;
1208 ent->write_proc = vicam_write_proc_gain;
1214 vicam_destroy_proc_entry(void *ptr)
1216 struct vicam_camera *cam = (struct vicam_camera *) ptr;
1219 if ( !cam->proc_dir )
1222 sprintf(name, "video%d", cam->vdev.minor);
1223 remove_proc_entry("shutter", cam->proc_dir);
1224 remove_proc_entry("gain", cam->proc_dir);
1225 remove_proc_entry(name,vicam_proc_root);
1226 cam->proc_dir = NULL;
1231 static inline void vicam_create_proc_root(void) { }
1232 static inline void vicam_destroy_proc_root(void) { }
1233 static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
1234 static inline void vicam_destroy_proc_entry(void *ptr) { }
1237 static const struct file_operations vicam_fops = {
1238 .owner = THIS_MODULE,
1240 .release = vicam_close,
1243 .ioctl = vicam_ioctl,
1244 .compat_ioctl = v4l_compat_ioctl32,
1245 .llseek = no_llseek,
1248 static struct video_device vicam_template = {
1249 .owner = THIS_MODULE,
1250 .name = "ViCam-based USB Camera",
1251 .type = VID_TYPE_CAPTURE,
1252 .hardware = VID_HARDWARE_VICAM,
1253 .fops = &vicam_fops,
1257 /* table of devices that work with this driver */
1258 static struct usb_device_id vicam_table[] = {
1259 {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1260 {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
1261 {} /* Terminating entry */
1264 MODULE_DEVICE_TABLE(usb, vicam_table);
1266 static struct usb_driver vicam_driver = {
1268 .probe = vicam_probe,
1269 .disconnect = vicam_disconnect,
1270 .id_table = vicam_table
1275 * @intf: the interface
1276 * @id: the device id
1278 * Called by the usb core when a new device is connected that it thinks
1279 * this driver might be interested in.
1282 vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
1284 struct usb_device *dev = interface_to_usbdev(intf);
1285 int bulkEndpoint = 0;
1286 const struct usb_host_interface *interface;
1287 const struct usb_endpoint_descriptor *endpoint;
1288 struct vicam_camera *cam;
1290 printk(KERN_INFO "ViCam based webcam connected\n");
1292 interface = intf->cur_altsetting;
1294 DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1295 interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
1296 endpoint = &interface->endpoint[0].desc;
1298 if ((endpoint->bEndpointAddress & 0x80) &&
1299 ((endpoint->bmAttributes & 3) == 0x02)) {
1300 /* we found a bulk in endpoint */
1301 bulkEndpoint = endpoint->bEndpointAddress;
1304 "No bulk in endpoint was found ?! (this is bad)\n");
1308 kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1310 "could not allocate kernel memory for vicam_camera struct\n");
1314 memset(cam, 0, sizeof (struct vicam_camera));
1316 cam->shutter_speed = 15;
1318 mutex_init(&cam->cam_lock);
1320 memcpy(&cam->vdev, &vicam_template,
1321 sizeof (vicam_template));
1322 cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only
1325 cam->bulkEndpoint = bulkEndpoint;
1327 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1329 printk(KERN_WARNING "video_register_device failed\n");
1333 vicam_create_proc_entry(cam);
1335 printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1337 usb_set_intfdata (intf, cam);
1343 vicam_disconnect(struct usb_interface *intf)
1346 struct vicam_camera *cam = usb_get_intfdata (intf);
1347 usb_set_intfdata (intf, NULL);
1349 /* we must unregister the device before taking its
1350 * cam_lock. This is because the video open call
1351 * holds the same lock as video unregister. if we
1352 * unregister inside of the cam_lock and open also
1353 * uses the cam_lock, we get deadlock.
1356 video_unregister_device(&cam->vdev);
1358 /* stop the camera from being used */
1360 mutex_lock(&cam->cam_lock);
1362 /* mark the camera as gone */
1366 vicam_destroy_proc_entry(cam);
1368 /* the only thing left to do is synchronize with
1369 * our close/release function on who should release
1370 * the camera memory. if there are any users using the
1371 * camera, it's their job. if there are no users,
1375 open_count = cam->open_count;
1377 mutex_unlock(&cam->cam_lock);
1383 printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1389 usb_vicam_init(void)
1392 DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1393 vicam_create_proc_root();
1394 retval = usb_register(&vicam_driver);
1396 printk(KERN_WARNING "usb_register failed!\n");
1401 usb_vicam_exit(void)
1404 "ViCam-based WebCam driver shutdown\n");
1406 usb_deregister(&vicam_driver);
1407 vicam_destroy_proc_root();
1410 module_init(usb_vicam_init);
1411 module_exit(usb_vicam_exit);
1413 MODULE_AUTHOR(DRIVER_AUTHOR);
1414 MODULE_DESCRIPTION(DRIVER_DESC);
1415 MODULE_LICENSE("GPL");