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
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 * This source code is based heavily on the CPiA webcam driver which was
26 * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
28 * Portions of this code were also copied from usbvideo.c
30 * Special thanks to the the whole team at Sourceforge for help making
31 * this driver become a reality. Notably:
32 * Andy Armstrong who reverse engineered the color encoding and
33 * Pavel Machek and Chris Cheney who worked on reverse engineering the
34 * camera controls and wrote the first generation driver.
37 #include <linux/kernel.h>
38 #include <linux/module.h>
39 #include <linux/init.h>
40 #include <linux/videodev.h>
41 #include <linux/usb.h>
42 #include <linux/vmalloc.h>
43 #include <linux/slab.h>
44 #include <linux/proc_fs.h>
45 #include <linux/mutex.h>
48 // #define VICAM_DEBUG
51 #define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
52 #define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
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
64 #define VICAM_BYTES_PER_PIXEL 3
65 #define VICAM_MAX_READ_SIZE (512*242+128)
66 #define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
67 #define VICAM_FRAMES 2
69 #define VICAM_HEADER_SIZE 64
71 #define clamp( x, l, h ) max_t( __typeof__( x ), \
73 min_t( __typeof__( x ), \
77 /* Not sure what all the bytes in these char
78 * arrays do, but they're necessary to make
82 static unsigned char setup1[] = {
83 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
84 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
85 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
86 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
87 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
90 static unsigned char setup2[] = {
91 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
95 static unsigned char setup3[] = {
96 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
99 static unsigned char setup4[] = {
100 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
101 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
102 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
103 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
104 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
105 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
106 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
107 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
108 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
109 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
110 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
111 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
112 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
113 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
114 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
115 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
116 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
117 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
118 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
119 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
120 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
121 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
122 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
123 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
124 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
125 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
126 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
127 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
128 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
129 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
130 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
131 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
132 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
133 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
134 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
135 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
136 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
137 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
138 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
139 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
140 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
141 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
142 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
143 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
144 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
145 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
146 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
147 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
148 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
149 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
150 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
151 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
152 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
153 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
154 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
155 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
156 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
157 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
158 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
159 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
160 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
161 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
162 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
163 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
164 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
165 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
166 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
167 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
168 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
169 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
170 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
171 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
172 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
173 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
174 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
175 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
176 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
177 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
178 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
179 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
180 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
181 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
182 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
183 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
184 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
185 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
186 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
187 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
188 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
189 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
190 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
191 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
192 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
193 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
194 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
195 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
196 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
197 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
198 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
199 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
200 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
201 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
202 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
203 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
204 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
205 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
206 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
207 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
208 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
209 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
210 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
211 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
212 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
213 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
214 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
215 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
216 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
217 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
218 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
219 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
220 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
221 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
222 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
223 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
224 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
225 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
226 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
227 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
228 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
229 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
230 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
231 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
232 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
233 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
234 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
235 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
236 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
237 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
238 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
239 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
240 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
241 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
242 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
243 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
244 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
245 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
246 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
247 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
248 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
249 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
250 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
251 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
252 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
253 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
254 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
255 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
256 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
257 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
258 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
259 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
260 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
261 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
262 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
263 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
264 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
265 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
266 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
267 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
268 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
269 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
270 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
271 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
272 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
273 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
274 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
275 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
276 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
277 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
278 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
279 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
280 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
281 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
282 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
283 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
284 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
285 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
286 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
287 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
288 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 static unsigned char setup5[] = {
314 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
315 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
316 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
317 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
318 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
319 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
320 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
321 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
322 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
323 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
324 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
325 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
326 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
327 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
328 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
329 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
330 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
331 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
332 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
333 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
334 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
335 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
336 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
337 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
338 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
339 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
340 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
341 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
342 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
343 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
344 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
345 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
346 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
347 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
348 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
349 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
350 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
351 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
352 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
355 /* rvmalloc / rvfree copied from usbvideo.c
357 * Not sure why these are not yet non-statics which I can reference through
358 * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime
362 static void *rvmalloc(unsigned long size)
367 size = PAGE_ALIGN(size);
368 mem = vmalloc_32(size);
372 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
373 adr = (unsigned long) mem;
375 SetPageReserved(vmalloc_to_page((void *)adr));
383 static void rvfree(void *mem, unsigned long size)
390 adr = (unsigned long) mem;
391 while ((long) size > 0) {
392 ClearPageReserved(vmalloc_to_page((void *)adr));
399 struct vicam_camera {
400 u16 shutter_speed; // capture shutter speed
401 u16 gain; // capture gain
403 u8 *raw_image; // raw data captured from the camera
404 u8 *framebuf; // processed data in RGB24 format
405 u8 *cntrlbuf; // area used to send control msgs
407 struct video_device vdev; // v4l video device
408 struct usb_device *udev; // usb device
410 /* guard against simultaneous accesses to the camera */
411 struct mutex cam_lock;
418 #if defined(CONFIG_VIDEO_PROC_FS)
419 struct proc_dir_entry *proc_dir;
424 static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
425 static void vicam_disconnect(struct usb_interface *intf);
426 static void read_frame(struct vicam_camera *cam, int framenum);
427 static void vicam_decode_color(const u8 *, u8 *);
429 static int __send_control_msg(struct vicam_camera *cam,
438 /* cp must be memory that has been allocated by kmalloc */
440 status = usb_control_msg(cam->udev,
441 usb_sndctrlpipe(cam->udev, 0),
443 USB_DIR_OUT | USB_TYPE_VENDOR |
444 USB_RECIP_DEVICE, value, index,
447 status = min(status, 0);
450 printk(KERN_INFO "Failed sending control message, error %d.\n",
457 static int send_control_msg(struct vicam_camera *cam,
464 int status = -ENODEV;
465 mutex_lock(&cam->cam_lock);
467 status = __send_control_msg(cam, request, value,
470 mutex_unlock(&cam->cam_lock);
474 initialize_camera(struct vicam_camera *cam)
480 { .data = setup1, .size = sizeof(setup1) },
481 { .data = setup2, .size = sizeof(setup2) },
482 { .data = setup3, .size = sizeof(setup3) },
483 { .data = setup4, .size = sizeof(setup4) },
484 { .data = setup5, .size = sizeof(setup5) },
485 { .data = setup3, .size = sizeof(setup3) },
486 { .data = NULL, .size = 0 }
491 for (i = 0, err = 0; firmware[i].data && !err; i++) {
492 memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
494 err = send_control_msg(cam, 0xff, 0, 0,
495 cam->cntrlbuf, firmware[i].size);
502 set_camera_power(struct vicam_camera *cam, int state)
506 if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
510 send_control_msg(cam, 0x55, 1, 0, NULL, 0);
517 vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
519 void __user *user_arg = (void __user *)arg;
520 struct vicam_camera *cam = file->private_data;
527 /* query capabilities */
530 struct video_capability b;
533 memset(&b, 0, sizeof(b));
534 strcpy(b.name, "ViCam-based Camera");
535 b.type = VID_TYPE_CAPTURE;
538 b.maxwidth = 320; /* VIDEOSIZE_CIF */
540 b.minwidth = 320; /* VIDEOSIZE_48_48 */
543 if (copy_to_user(user_arg, &b, sizeof(b)))
548 /* get/set video source - we are a camera and nothing else */
551 struct video_channel v;
553 DBG("VIDIOCGCHAN\n");
554 if (copy_from_user(&v, user_arg, sizeof(v))) {
558 if (v.channel != 0) {
564 strcpy(v.name, "Camera");
567 v.type = VIDEO_TYPE_CAMERA;
570 if (copy_to_user(user_arg, &v, sizeof(v)))
579 if (copy_from_user(&v, user_arg, sizeof(v)))
581 DBG("VIDIOCSCHAN %d\n", v);
583 if (retval == 0 && v != 0)
589 /* image properties */
592 struct video_picture vp;
593 DBG("VIDIOCGPICT\n");
594 memset(&vp, 0, sizeof (struct video_picture));
595 vp.brightness = cam->gain << 8;
597 vp.palette = VIDEO_PALETTE_RGB24;
598 if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
605 struct video_picture vp;
607 if (copy_from_user(&vp, user_arg, sizeof(vp))) {
612 DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
615 cam->gain = vp.brightness >> 8;
618 || vp.palette != VIDEO_PALETTE_RGB24)
624 /* get/set capture window */
627 struct video_window vw;
639 if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
642 // I'm not sure what the deal with a capture window is, it is very poorly described
643 // in the doc. So I won't support it now.
650 struct video_window vw;
652 if (copy_from_user(&vw, user_arg, sizeof(vw))) {
657 DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
659 if ( vw.width != 320 || vw.height != 240 )
668 struct video_mbuf vm;
671 DBG("VIDIOCGMBUF\n");
672 memset(&vm, 0, sizeof (vm));
674 VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
675 vm.frames = VICAM_FRAMES;
676 for (i = 0; i < VICAM_FRAMES; i++)
677 vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
679 if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
687 struct video_mmap vm;
690 if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
695 DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
697 if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
700 // in theory right here we'd start the image capturing
701 // (fill in a bulk urb and submit it asynchronously)
703 // Instead we're going to do a total hack job for now and
704 // retrieve the frame in VIDIOCSYNC
713 if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
717 DBG("VIDIOCSYNC: %d\n", frame);
719 read_frame(cam, frame);
720 vicam_decode_color(cam->raw_image,
722 frame * VICAM_MAX_FRAME_SIZE );
727 /* pointless to implement overlay with this camera */
735 /* tuner interface - we have none */
743 /* audio interface - we have none */
749 retval = -ENOIOCTLCMD;
757 vicam_open(struct inode *inode, struct file *file)
759 struct video_device *dev = video_devdata(file);
760 struct vicam_camera *cam =
761 (struct vicam_camera *) dev->priv;
766 "vicam video_device improperly initialized");
769 /* the videodev_lock held above us protects us from
770 * simultaneous opens...for now. we probably shouldn't
771 * rely on this fact forever.
774 if (cam->open_count > 0) {
776 "vicam_open called on already opened camera");
780 cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
781 if (!cam->raw_image) {
785 cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
786 if (!cam->framebuf) {
787 kfree(cam->raw_image);
791 cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
792 if (!cam->cntrlbuf) {
793 kfree(cam->raw_image);
794 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
798 // First upload firmware, then turn the camera on
800 if (!cam->is_initialized) {
801 initialize_camera(cam);
803 cam->is_initialized = 1;
806 set_camera_power(cam, 1);
808 cam->needsDummyRead = 1;
811 file->private_data = cam;
817 vicam_close(struct inode *inode, struct file *file)
819 struct vicam_camera *cam = file->private_data;
821 struct usb_device *udev;
825 /* it's not the end of the world if
826 * we fail to turn the camera off.
829 set_camera_power(cam, 0);
831 kfree(cam->raw_image);
832 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
833 kfree(cam->cntrlbuf);
835 mutex_lock(&cam->cam_lock);
838 open_count = cam->open_count;
841 mutex_unlock(&cam->cam_lock);
843 if (!open_count && !udev) {
850 static void vicam_decode_color(const u8 *data, u8 *rgb)
852 /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
853 * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
861 data += VICAM_HEADER_SIZE;
863 for( i = 0; i < 240; i++, data += 512 ) {
864 const int y = ( i * 242 ) / 240;
869 if ( y == 242 - 1 ) {
876 for ( j = 0; j < 320; j++, rgb += 3 ) {
877 const int x = ( j * 512 ) / 320;
878 const u8 * const src = &data[x];
880 if ( x == 512 - 1 ) {
884 Cr = ( src[prevX] - src[0] ) +
885 ( src[nextX] - src[0] );
888 Cb = ( src[prevY] - src[prevX + prevY] ) +
889 ( src[prevY] - src[nextX + prevY] ) +
890 ( src[nextY] - src[prevX + nextY] ) +
891 ( src[nextY] - src[nextX + nextY] );
894 Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
902 if ( ( x ^ i ) & 1 ) {
907 rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
908 500 ) / 900, 0, 255 );
909 rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
911 500 ) / 1000, 0, 255 );
912 rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
913 500 ) / 1300, 0, 255 );
923 read_frame(struct vicam_camera *cam, int framenum)
925 unsigned char *request = cam->cntrlbuf;
930 if (cam->needsDummyRead) {
931 cam->needsDummyRead = 0;
932 read_frame(cam, framenum);
935 memset(request, 0, 16);
936 request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
938 request[1] = 0; // 512x242 capture
940 request[2] = 0x90; // the function of these two bytes
941 request[3] = 0x07; // is not yet understood
943 if (cam->shutter_speed > 60) {
946 ((-15631900 / cam->shutter_speed) + 260533) / 1000;
947 request[4] = realShutter & 0xFF;
948 request[5] = (realShutter >> 8) & 0xFF;
953 realShutter = 15600 / cam->shutter_speed - 1;
956 request[6] = realShutter & 0xFF;
957 request[7] = realShutter >> 8;
960 // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
962 // bytes 9-15 do not seem to affect exposure or image quality
964 mutex_lock(&cam->cam_lock);
970 n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
974 " Problem sending frame capture control message");
978 n = usb_bulk_msg(cam->udev,
979 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
981 512 * 242 + 128, &actual_length, 10000);
984 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
989 mutex_unlock(&cam->cam_lock);
993 vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
995 struct vicam_camera *cam = file->private_data;
997 DBG("read %d bytes.\n", (int) count);
999 if (*ppos >= VICAM_MAX_FRAME_SIZE) {
1006 vicam_decode_color(cam->raw_image,
1008 0 * VICAM_MAX_FRAME_SIZE);
1011 count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
1013 if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
1019 if (count == VICAM_MAX_FRAME_SIZE) {
1028 vicam_mmap(struct file *file, struct vm_area_struct *vma)
1030 // TODO: allocate the raw frame buffer if necessary
1031 unsigned long page, pos;
1032 unsigned long start = vma->vm_start;
1033 unsigned long size = vma->vm_end-vma->vm_start;
1034 struct vicam_camera *cam = file->private_data;
1039 DBG("vicam_mmap: %ld\n", size);
1041 /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1042 * to the size the application requested for mmap and it was screwing apps up.
1043 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1047 pos = (unsigned long)cam->framebuf;
1049 page = vmalloc_to_pfn((void *)pos);
1050 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1055 if (size > PAGE_SIZE)
1064 #if defined(CONFIG_VIDEO_PROC_FS)
1066 static struct proc_dir_entry *vicam_proc_root = NULL;
1068 static int vicam_read_helper(char *page, char **start, off_t off,
1069 int count, int *eof, int value)
1074 out += sprintf(out, "%d",value);
1085 *start = page + off;
1089 static int vicam_read_proc_shutter(char *page, char **start, off_t off,
1090 int count, int *eof, void *data)
1092 return vicam_read_helper(page,start,off,count,eof,
1093 ((struct vicam_camera *)data)->shutter_speed);
1096 static int vicam_read_proc_gain(char *page, char **start, off_t off,
1097 int count, int *eof, void *data)
1099 return vicam_read_helper(page,start,off,count,eof,
1100 ((struct vicam_camera *)data)->gain);
1104 vicam_write_proc_shutter(struct file *file, const char *buffer,
1105 unsigned long count, void *data)
1109 struct vicam_camera *cam = (struct vicam_camera *) data;
1114 if (copy_from_user(kbuf, buffer, count))
1117 stmp = (u16) simple_strtoul(kbuf, NULL, 10);
1118 if (stmp < 4 || stmp > 32000)
1121 cam->shutter_speed = stmp;
1127 vicam_write_proc_gain(struct file *file, const char *buffer,
1128 unsigned long count, void *data)
1133 struct vicam_camera *cam = (struct vicam_camera *) data;
1138 if (copy_from_user(kbuf, buffer, count))
1141 gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
1150 vicam_create_proc_root(void)
1152 vicam_proc_root = proc_mkdir("video/vicam", NULL);
1154 if (vicam_proc_root)
1155 vicam_proc_root->owner = THIS_MODULE;
1158 "could not create /proc entry for vicam!");
1162 vicam_destroy_proc_root(void)
1164 if (vicam_proc_root)
1165 remove_proc_entry("video/vicam", 0);
1169 vicam_create_proc_entry(struct vicam_camera *cam)
1172 struct proc_dir_entry *ent;
1174 DBG(KERN_INFO "vicam: creating proc entry\n");
1176 if (!vicam_proc_root || !cam) {
1178 "vicam: could not create proc entry, %s pointer is null.\n",
1179 (!cam ? "camera" : "root"));
1183 sprintf(name, "video%d", cam->vdev.minor);
1185 cam->proc_dir = proc_mkdir(name, vicam_proc_root);
1187 if ( !cam->proc_dir )
1188 return; // FIXME: We should probably return an error here
1190 ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
1194 ent->read_proc = vicam_read_proc_shutter;
1195 ent->write_proc = vicam_write_proc_shutter;
1199 ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
1203 ent->read_proc = vicam_read_proc_gain;
1204 ent->write_proc = vicam_write_proc_gain;
1210 vicam_destroy_proc_entry(void *ptr)
1212 struct vicam_camera *cam = (struct vicam_camera *) ptr;
1215 if ( !cam->proc_dir )
1218 sprintf(name, "video%d", cam->vdev.minor);
1219 remove_proc_entry("shutter", cam->proc_dir);
1220 remove_proc_entry("gain", cam->proc_dir);
1221 remove_proc_entry(name,vicam_proc_root);
1222 cam->proc_dir = NULL;
1227 static inline void vicam_create_proc_root(void) { }
1228 static inline void vicam_destroy_proc_root(void) { }
1229 static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
1230 static inline void vicam_destroy_proc_entry(void *ptr) { }
1233 static struct file_operations vicam_fops = {
1234 .owner = THIS_MODULE,
1236 .release = vicam_close,
1239 .ioctl = vicam_ioctl,
1240 .compat_ioctl = v4l_compat_ioctl32,
1241 .llseek = no_llseek,
1244 static struct video_device vicam_template = {
1245 .owner = THIS_MODULE,
1246 .name = "ViCam-based USB Camera",
1247 .type = VID_TYPE_CAPTURE,
1248 .hardware = VID_HARDWARE_VICAM,
1249 .fops = &vicam_fops,
1253 /* table of devices that work with this driver */
1254 static struct usb_device_id vicam_table[] = {
1255 {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1256 {} /* Terminating entry */
1259 MODULE_DEVICE_TABLE(usb, vicam_table);
1261 static struct usb_driver vicam_driver = {
1263 .probe = vicam_probe,
1264 .disconnect = vicam_disconnect,
1265 .id_table = vicam_table
1270 * @intf: the interface
1271 * @id: the device id
1273 * Called by the usb core when a new device is connected that it thinks
1274 * this driver might be interested in.
1277 vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
1279 struct usb_device *dev = interface_to_usbdev(intf);
1280 int bulkEndpoint = 0;
1281 const struct usb_host_interface *interface;
1282 const struct usb_endpoint_descriptor *endpoint;
1283 struct vicam_camera *cam;
1285 printk(KERN_INFO "ViCam based webcam connected\n");
1287 interface = intf->cur_altsetting;
1289 DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1290 interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
1291 endpoint = &interface->endpoint[0].desc;
1293 if ((endpoint->bEndpointAddress & 0x80) &&
1294 ((endpoint->bmAttributes & 3) == 0x02)) {
1295 /* we found a bulk in endpoint */
1296 bulkEndpoint = endpoint->bEndpointAddress;
1299 "No bulk in endpoint was found ?! (this is bad)\n");
1303 kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1305 "could not allocate kernel memory for vicam_camera struct\n");
1309 memset(cam, 0, sizeof (struct vicam_camera));
1311 cam->shutter_speed = 15;
1313 mutex_init(&cam->cam_lock);
1315 memcpy(&cam->vdev, &vicam_template,
1316 sizeof (vicam_template));
1317 cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only
1320 cam->bulkEndpoint = bulkEndpoint;
1322 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1324 printk(KERN_WARNING "video_register_device failed\n");
1328 vicam_create_proc_entry(cam);
1330 printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1332 usb_set_intfdata (intf, cam);
1338 vicam_disconnect(struct usb_interface *intf)
1341 struct vicam_camera *cam = usb_get_intfdata (intf);
1342 usb_set_intfdata (intf, NULL);
1344 /* we must unregister the device before taking its
1345 * cam_lock. This is because the video open call
1346 * holds the same lock as video unregister. if we
1347 * unregister inside of the cam_lock and open also
1348 * uses the cam_lock, we get deadlock.
1351 video_unregister_device(&cam->vdev);
1353 /* stop the camera from being used */
1355 mutex_lock(&cam->cam_lock);
1357 /* mark the camera as gone */
1361 vicam_destroy_proc_entry(cam);
1363 /* the only thing left to do is synchronize with
1364 * our close/release function on who should release
1365 * the camera memory. if there are any users using the
1366 * camera, it's their job. if there are no users,
1370 open_count = cam->open_count;
1372 mutex_unlock(&cam->cam_lock);
1378 printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1384 usb_vicam_init(void)
1387 DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1388 vicam_create_proc_root();
1389 retval = usb_register(&vicam_driver);
1391 printk(KERN_WARNING "usb_register failed!\n");
1396 usb_vicam_exit(void)
1399 "ViCam-based WebCam driver shutdown\n");
1401 usb_deregister(&vicam_driver);
1402 vicam_destroy_proc_root();
1405 module_init(usb_vicam_init);
1406 module_exit(usb_vicam_exit);
1408 MODULE_AUTHOR(DRIVER_AUTHOR);
1409 MODULE_DESCRIPTION(DRIVER_DESC);
1410 MODULE_LICENSE("GPL");