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");
770 /* the videodev_lock held above us protects us from
771 * simultaneous opens...for now. we probably shouldn't
772 * rely on this fact forever.
775 if (cam->open_count > 0) {
777 "vicam_open called on already opened camera");
781 cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
782 if (!cam->raw_image) {
786 cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
787 if (!cam->framebuf) {
788 kfree(cam->raw_image);
792 cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
793 if (!cam->cntrlbuf) {
794 kfree(cam->raw_image);
795 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
799 // First upload firmware, then turn the camera on
801 if (!cam->is_initialized) {
802 initialize_camera(cam);
804 cam->is_initialized = 1;
807 set_camera_power(cam, 1);
809 cam->needsDummyRead = 1;
812 file->private_data = cam;
818 vicam_close(struct inode *inode, struct file *file)
820 struct vicam_camera *cam = file->private_data;
822 struct usb_device *udev;
826 /* it's not the end of the world if
827 * we fail to turn the camera off.
830 set_camera_power(cam, 0);
832 kfree(cam->raw_image);
833 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
834 kfree(cam->cntrlbuf);
836 mutex_lock(&cam->cam_lock);
839 open_count = cam->open_count;
842 mutex_unlock(&cam->cam_lock);
844 if (!open_count && !udev) {
851 static void vicam_decode_color(const u8 *data, u8 *rgb)
853 /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
854 * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
862 data += VICAM_HEADER_SIZE;
864 for( i = 0; i < 240; i++, data += 512 ) {
865 const int y = ( i * 242 ) / 240;
870 if ( y == 242 - 1 ) {
877 for ( j = 0; j < 320; j++, rgb += 3 ) {
878 const int x = ( j * 512 ) / 320;
879 const u8 * const src = &data[x];
881 if ( x == 512 - 1 ) {
885 Cr = ( src[prevX] - src[0] ) +
886 ( src[nextX] - src[0] );
889 Cb = ( src[prevY] - src[prevX + prevY] ) +
890 ( src[prevY] - src[nextX + prevY] ) +
891 ( src[nextY] - src[prevX + nextY] ) +
892 ( src[nextY] - src[nextX + nextY] );
895 Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
903 if ( ( x ^ i ) & 1 ) {
908 rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
909 500 ) / 900, 0, 255 );
910 rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
912 500 ) / 1000, 0, 255 );
913 rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
914 500 ) / 1300, 0, 255 );
924 read_frame(struct vicam_camera *cam, int framenum)
926 unsigned char *request = cam->cntrlbuf;
931 if (cam->needsDummyRead) {
932 cam->needsDummyRead = 0;
933 read_frame(cam, framenum);
936 memset(request, 0, 16);
937 request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
939 request[1] = 0; // 512x242 capture
941 request[2] = 0x90; // the function of these two bytes
942 request[3] = 0x07; // is not yet understood
944 if (cam->shutter_speed > 60) {
947 ((-15631900 / cam->shutter_speed) + 260533) / 1000;
948 request[4] = realShutter & 0xFF;
949 request[5] = (realShutter >> 8) & 0xFF;
954 realShutter = 15600 / cam->shutter_speed - 1;
957 request[6] = realShutter & 0xFF;
958 request[7] = realShutter >> 8;
961 // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
963 // bytes 9-15 do not seem to affect exposure or image quality
965 mutex_lock(&cam->cam_lock);
971 n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
975 " Problem sending frame capture control message");
979 n = usb_bulk_msg(cam->udev,
980 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
982 512 * 242 + 128, &actual_length, 10000);
985 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
990 mutex_unlock(&cam->cam_lock);
994 vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
996 struct vicam_camera *cam = file->private_data;
998 DBG("read %d bytes.\n", (int) count);
1000 if (*ppos >= VICAM_MAX_FRAME_SIZE) {
1007 vicam_decode_color(cam->raw_image,
1009 0 * VICAM_MAX_FRAME_SIZE);
1012 count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
1014 if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
1020 if (count == VICAM_MAX_FRAME_SIZE) {
1029 vicam_mmap(struct file *file, struct vm_area_struct *vma)
1031 // TODO: allocate the raw frame buffer if necessary
1032 unsigned long page, pos;
1033 unsigned long start = vma->vm_start;
1034 unsigned long size = vma->vm_end-vma->vm_start;
1035 struct vicam_camera *cam = file->private_data;
1040 DBG("vicam_mmap: %ld\n", size);
1042 /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1043 * to the size the application requested for mmap and it was screwing apps up.
1044 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1048 pos = (unsigned long)cam->framebuf;
1050 page = vmalloc_to_pfn((void *)pos);
1051 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1056 if (size > PAGE_SIZE)
1065 #if defined(CONFIG_VIDEO_PROC_FS)
1067 static struct proc_dir_entry *vicam_proc_root = NULL;
1069 static int vicam_read_helper(char *page, char **start, off_t off,
1070 int count, int *eof, int value)
1075 out += sprintf(out, "%d",value);
1086 *start = page + off;
1090 static int vicam_read_proc_shutter(char *page, char **start, off_t off,
1091 int count, int *eof, void *data)
1093 return vicam_read_helper(page,start,off,count,eof,
1094 ((struct vicam_camera *)data)->shutter_speed);
1097 static int vicam_read_proc_gain(char *page, char **start, off_t off,
1098 int count, int *eof, void *data)
1100 return vicam_read_helper(page,start,off,count,eof,
1101 ((struct vicam_camera *)data)->gain);
1105 vicam_write_proc_shutter(struct file *file, const char *buffer,
1106 unsigned long count, void *data)
1110 struct vicam_camera *cam = (struct vicam_camera *) data;
1115 if (copy_from_user(kbuf, buffer, count))
1118 stmp = (u16) simple_strtoul(kbuf, NULL, 10);
1119 if (stmp < 4 || stmp > 32000)
1122 cam->shutter_speed = stmp;
1128 vicam_write_proc_gain(struct file *file, const char *buffer,
1129 unsigned long count, void *data)
1134 struct vicam_camera *cam = (struct vicam_camera *) data;
1139 if (copy_from_user(kbuf, buffer, count))
1142 gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
1151 vicam_create_proc_root(void)
1153 vicam_proc_root = proc_mkdir("video/vicam", NULL);
1155 if (vicam_proc_root)
1156 vicam_proc_root->owner = THIS_MODULE;
1159 "could not create /proc entry for vicam!");
1163 vicam_destroy_proc_root(void)
1165 if (vicam_proc_root)
1166 remove_proc_entry("video/vicam", 0);
1170 vicam_create_proc_entry(struct vicam_camera *cam)
1173 struct proc_dir_entry *ent;
1175 DBG(KERN_INFO "vicam: creating proc entry\n");
1177 if (!vicam_proc_root || !cam) {
1179 "vicam: could not create proc entry, %s pointer is null.\n",
1180 (!cam ? "camera" : "root"));
1184 sprintf(name, "video%d", cam->vdev.minor);
1186 cam->proc_dir = proc_mkdir(name, vicam_proc_root);
1188 if ( !cam->proc_dir )
1189 return; // FIXME: We should probably return an error here
1191 ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
1195 ent->read_proc = vicam_read_proc_shutter;
1196 ent->write_proc = vicam_write_proc_shutter;
1200 ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
1204 ent->read_proc = vicam_read_proc_gain;
1205 ent->write_proc = vicam_write_proc_gain;
1211 vicam_destroy_proc_entry(void *ptr)
1213 struct vicam_camera *cam = (struct vicam_camera *) ptr;
1216 if ( !cam->proc_dir )
1219 sprintf(name, "video%d", cam->vdev.minor);
1220 remove_proc_entry("shutter", cam->proc_dir);
1221 remove_proc_entry("gain", cam->proc_dir);
1222 remove_proc_entry(name,vicam_proc_root);
1223 cam->proc_dir = NULL;
1228 static inline void vicam_create_proc_root(void) { }
1229 static inline void vicam_destroy_proc_root(void) { }
1230 static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
1231 static inline void vicam_destroy_proc_entry(void *ptr) { }
1234 static struct file_operations vicam_fops = {
1235 .owner = THIS_MODULE,
1237 .release = vicam_close,
1240 .ioctl = vicam_ioctl,
1241 .compat_ioctl = v4l_compat_ioctl32,
1242 .llseek = no_llseek,
1245 static struct video_device vicam_template = {
1246 .owner = THIS_MODULE,
1247 .name = "ViCam-based USB Camera",
1248 .type = VID_TYPE_CAPTURE,
1249 .hardware = VID_HARDWARE_VICAM,
1250 .fops = &vicam_fops,
1254 /* table of devices that work with this driver */
1255 static struct usb_device_id vicam_table[] = {
1256 {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1257 {} /* Terminating entry */
1260 MODULE_DEVICE_TABLE(usb, vicam_table);
1262 static struct usb_driver vicam_driver = {
1264 .probe = vicam_probe,
1265 .disconnect = vicam_disconnect,
1266 .id_table = vicam_table
1271 * @intf: the interface
1272 * @id: the device id
1274 * Called by the usb core when a new device is connected that it thinks
1275 * this driver might be interested in.
1278 vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
1280 struct usb_device *dev = interface_to_usbdev(intf);
1281 int bulkEndpoint = 0;
1282 const struct usb_host_interface *interface;
1283 const struct usb_endpoint_descriptor *endpoint;
1284 struct vicam_camera *cam;
1286 printk(KERN_INFO "ViCam based webcam connected\n");
1288 interface = intf->cur_altsetting;
1290 DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1291 interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
1292 endpoint = &interface->endpoint[0].desc;
1294 if ((endpoint->bEndpointAddress & 0x80) &&
1295 ((endpoint->bmAttributes & 3) == 0x02)) {
1296 /* we found a bulk in endpoint */
1297 bulkEndpoint = endpoint->bEndpointAddress;
1300 "No bulk in endpoint was found ?! (this is bad)\n");
1304 kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1306 "could not allocate kernel memory for vicam_camera struct\n");
1310 memset(cam, 0, sizeof (struct vicam_camera));
1312 cam->shutter_speed = 15;
1314 mutex_init(&cam->cam_lock);
1316 memcpy(&cam->vdev, &vicam_template,
1317 sizeof (vicam_template));
1318 cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only
1321 cam->bulkEndpoint = bulkEndpoint;
1323 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1325 printk(KERN_WARNING "video_register_device failed\n");
1329 vicam_create_proc_entry(cam);
1331 printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1333 usb_set_intfdata (intf, cam);
1339 vicam_disconnect(struct usb_interface *intf)
1342 struct vicam_camera *cam = usb_get_intfdata (intf);
1343 usb_set_intfdata (intf, NULL);
1345 /* we must unregister the device before taking its
1346 * cam_lock. This is because the video open call
1347 * holds the same lock as video unregister. if we
1348 * unregister inside of the cam_lock and open also
1349 * uses the cam_lock, we get deadlock.
1352 video_unregister_device(&cam->vdev);
1354 /* stop the camera from being used */
1356 mutex_lock(&cam->cam_lock);
1358 /* mark the camera as gone */
1362 vicam_destroy_proc_entry(cam);
1364 /* the only thing left to do is synchronize with
1365 * our close/release function on who should release
1366 * the camera memory. if there are any users using the
1367 * camera, it's their job. if there are no users,
1371 open_count = cam->open_count;
1373 mutex_unlock(&cam->cam_lock);
1379 printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1385 usb_vicam_init(void)
1388 DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1389 vicam_create_proc_root();
1390 retval = usb_register(&vicam_driver);
1392 printk(KERN_WARNING "usb_register failed!\n");
1397 usb_vicam_exit(void)
1400 "ViCam-based WebCam driver shutdown\n");
1402 usb_deregister(&vicam_driver);
1403 vicam_destroy_proc_root();
1406 module_init(usb_vicam_init);
1407 module_exit(usb_vicam_exit);
1409 MODULE_AUTHOR(DRIVER_AUTHOR);
1410 MODULE_DESCRIPTION(DRIVER_DESC);
1411 MODULE_LICENSE("GPL");