1 /*
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)
8 *
9 * Supports 3COM HomeConnect PC Digital WebCam
10 *
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.
15 *
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.
20 *
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.
24 *
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
27 *
28 * Portions of this code were also copied from usbvideo.c
29 *
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.
35 */
36
37 #include <linux/kernel.h>
38 #include <linux/wrapper.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 "usbvideo.h"
47
48 // #define VICAM_DEBUG
49
50 #ifndef MODULE_LICENSE
51 #define MODULE_LICENSE(a)
52 #endif
53
54 #ifndef bool
55 #define bool int
56 #endif
57
58 #ifdef VICAM_DEBUG
59 #define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
60 #define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
61 #else
62 #define DBG(fmn,args...) do {} while(0)
63 #endif
64
65 /* Version Information */
66 #define DRIVER_VERSION "v1.0"
67 #define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org"
68 #define DRIVER_DESC "ViCam WebCam Driver"
69
70 /* Define these values to match your device */
71 #define USB_VICAM_VENDOR_ID 0x04c1
72 #define USB_VICAM_PRODUCT_ID 0x009d
73
74 #define VICAM_BYTES_PER_PIXEL 3
75 #define VICAM_MAX_READ_SIZE (512*242+128)
76 #define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
77 #define VICAM_FRAMES 2
78
79 /* Not sure what all the bytes in these char
80 * arrays do, but they're necessary to make
81 * the camera work.
82 */
83
84 static unsigned char setup1[] = {
85 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
86 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
87 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
88 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
89 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
90 };
91
92 static unsigned char setup2[] = {
93 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
94 0x00, 0x00
95 };
96
97 static unsigned char setup3[] = {
98 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
99 };
100
101 static unsigned char setup4[] = {
102 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
103 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
104 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
105 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
106 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
107 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
108 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
109 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
110 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
111 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
112 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
113 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
114 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
115 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
116 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
117 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
118 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
119 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
120 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
121 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
122 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
123 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
124 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
125 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
126 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
127 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
128 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
129 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
130 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
131 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
132 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
133 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
134 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
135 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
136 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
137 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
138 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
139 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
140 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
141 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
142 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
143 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
144 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
145 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
146 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
147 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
148 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
149 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
150 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
151 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
152 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
153 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
154 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
155 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
156 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
157 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
158 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
159 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
160 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
161 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
162 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
163 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
164 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
165 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
166 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
167 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
168 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
169 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
170 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
171 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
172 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
173 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
174 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
175 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
176 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
177 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
178 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
179 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
180 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
181 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
182 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
183 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
184 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
185 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
186 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
187 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
188 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
189 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
190 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
191 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
192 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
193 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
194 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
195 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
196 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
197 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
198 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
199 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
200 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
201 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
202 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
203 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
204 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
205 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
206 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
207 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
208 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
209 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
210 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
211 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
212 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
213 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
214 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
215 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
216 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
217 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
218 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
219 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
220 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
221 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
222 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
223 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
224 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
225 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
226 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
227 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
228 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
229 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
230 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
231 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
232 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
233 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
234 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
235 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
236 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
237 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
238 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
239 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
240 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
241 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
242 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
243 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
244 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
245 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
246 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
247 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
248 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
249 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
250 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
251 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
252 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
253 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
254 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
255 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
256 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
257 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
258 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
259 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
260 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
261 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
262 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
263 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
264 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
265 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
266 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
267 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
268 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
269 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
270 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
271 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
272 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
273 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
274 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
275 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
276 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
277 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
278 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
279 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
280 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
281 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
282 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
283 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
284 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
285 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
286 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
287 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
288 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
289 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
290 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 };
314
315 static unsigned char setup5[] = {
316 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
317 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
318 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
319 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
320 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
321 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
322 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
323 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
324 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
325 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
326 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
327 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
328 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
329 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
330 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
331 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
332 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
333 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
334 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
335 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
336 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
337 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
338 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
339 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
340 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
341 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
342 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
343 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
344 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
345 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
346 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
347 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
348 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
349 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
350 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
351 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
352 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
353 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
354 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
355 };
356
357 struct vicam_camera {
358 u16 shutter_speed; // capture shutter speed
359 u16 gain; // capture gain
360
361 u8 *raw_image; // raw data captured from the camera
362 u8 *framebuf; // processed data in RGB24 format
363
364 struct video_device vdev; // v4l video device
365 struct usb_device *udev; // usb device
366
367 struct semaphore busy_lock; // guard against SMP multithreading
368
369 bool is_initialized;
370 bool is_removed;
371 bool is_opened;
372 u8 bulkEndpoint;
373 bool needsDummyRead;
374
375 u32 framebuf_size; // # of valid bytes in framebuf
376 u32 framebuf_read_start; // position in frame buf that a read is happening at.
377
378 #ifdef CONFIG_PROC_FS
379 struct proc_dir_entry *proc_entry;
380 #endif
381
382 };
383
384 static void *vicam_probe(struct usb_device *dev, unsigned int ifnum,
385 const struct usb_device_id *id);
386 static void vicam_disconnect(struct usb_device *dev, void *ptr);
387 static void read_frame(struct vicam_camera *cam, int framenum);
388 static void vicam_purge(struct vicam_camera *cam);
389
390 static int
send_control_msg(struct usb_device * udev,u8 request,u16 value,u16 index,unsigned char * cp,u16 size)391 send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index,
392 unsigned char *cp, u16 size)
393 {
394 int status;
395
396 // for reasons not yet known to me, you can't send USB control messages
397 // with data in the module (if you are compiled as a module). Whatever
398 // the reason, copying it to memory allocated as kernel memory then
399 // doing the usb control message fixes the problem.
400
401 unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL);
402 memcpy(transfer_buffer, cp, size);
403
404 status = usb_control_msg(udev,
405 usb_sndctrlpipe(udev, 0),
406 request,
407 USB_DIR_OUT | USB_TYPE_VENDOR |
408 USB_RECIP_DEVICE, value, index,
409 transfer_buffer, size, HZ);
410
411 kfree(transfer_buffer);
412
413 if (status < 0) {
414 printk(KERN_INFO "Failed sending control message, error %d.\n",
415 status);
416 }
417
418 return status;
419 }
420
421 static int
initialize_camera(struct vicam_camera * cam)422 initialize_camera(struct vicam_camera *cam)
423 {
424 struct usb_device *udev = cam->udev;
425 int status;
426
427 if ((status =
428 send_control_msg(udev, 0xff, 0, 0, setup1, sizeof (setup1))) < 0)
429 return status;
430 if ((status =
431 send_control_msg(udev, 0xff, 0, 0, setup2, sizeof (setup2))) < 0)
432 return status;
433 if ((status =
434 send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
435 return status;
436 if ((status =
437 send_control_msg(udev, 0xff, 0, 0, setup4, sizeof (setup4))) < 0)
438 return status;
439 if ((status =
440 send_control_msg(udev, 0xff, 0, 0, setup5, sizeof (setup5))) < 0)
441 return status;
442 if ((status =
443 send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
444 return status;
445
446 return 0;
447 }
448
449 static int
set_camera_power(struct vicam_camera * cam,int state)450 set_camera_power(struct vicam_camera *cam, int state)
451 {
452 int status;
453
454 if ((status = send_control_msg(cam->udev, 0x50, state, 0, NULL, 0)) < 0)
455 return status;
456
457 if (state) {
458 send_control_msg(cam->udev, 0x55, 1, 0, NULL, 0);
459 }
460
461 return 0;
462 }
463
464 static int
vicam_ioctl(struct video_device * dev,unsigned int ioctlnr,void * arg)465 vicam_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
466 {
467 struct vicam_camera *cam = dev->priv;
468 int retval = 0;
469
470 if (!cam)
471 return -ENODEV;
472
473 /* make this _really_ smp-safe */
474 if (down_interruptible(&cam->busy_lock))
475 return -EINTR;
476
477 switch (ioctlnr) {
478 /* query capabilites */
479 case VIDIOCGCAP:
480 {
481 struct video_capability b;
482
483 DBG("VIDIOCGCAP\n");
484 memset(&b, 0, sizeof(b));
485 strcpy(b.name, "ViCam-based Camera");
486 b.type = VID_TYPE_CAPTURE;
487 b.channels = 1;
488 b.audios = 0;
489 b.maxwidth = 320; /* VIDEOSIZE_CIF */
490 b.maxheight = 240;
491 b.minwidth = 320; /* VIDEOSIZE_48_48 */
492 b.minheight = 240;
493
494 if (copy_to_user(arg, &b, sizeof (b)))
495 retval = -EFAULT;
496
497 break;
498 }
499 /* get/set video source - we are a camera and nothing else */
500 case VIDIOCGCHAN:
501 {
502 struct video_channel v;
503
504 DBG("VIDIOCGCHAN\n");
505 if (copy_from_user(&v, arg, sizeof (v))) {
506 retval = -EFAULT;
507 break;
508 }
509 if (v.channel != 0) {
510 retval = -EINVAL;
511 break;
512 }
513
514 v.channel = 0;
515 strcpy(v.name, "Camera");
516 v.tuners = 0;
517 v.flags = 0;
518 v.type = VIDEO_TYPE_CAMERA;
519 v.norm = 0;
520
521 if (copy_to_user(arg, &v, sizeof (v)))
522 retval = -EFAULT;
523 break;
524 }
525
526 case VIDIOCSCHAN:
527 {
528 int v;
529
530 if (copy_from_user(&v, arg, sizeof (v)))
531 retval = -EFAULT;
532 DBG("VIDIOCSCHAN %d\n", v);
533
534 if (retval == 0 && v != 0)
535 retval = -EINVAL;
536
537 break;
538 }
539
540 /* image properties */
541 case VIDIOCGPICT:
542 {
543 struct video_picture vp;
544 DBG("VIDIOCGPICT\n");
545 memset(&vp, 0, sizeof (struct video_picture));
546 vp.brightness = cam->gain << 8;
547 vp.depth = 24;
548 vp.palette = VIDEO_PALETTE_RGB24;
549 if (copy_to_user
550 (arg, &vp, sizeof (struct video_picture)))
551 retval = -EFAULT;
552 break;
553 }
554
555 case VIDIOCSPICT:
556 {
557 struct video_picture vp;
558
559 if(copy_from_user(&vp, (struct video_picture *) arg,
560 sizeof(struct video_picture)))
561 retval = -EFAULT;
562
563 else
564 {
565 DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
566 vp.palette);
567
568 cam->gain = vp.brightness >> 8;
569
570 if (vp.depth != 24
571 || vp.palette != VIDEO_PALETTE_RGB24)
572 retval = -EINVAL;
573 }
574
575 break;
576 }
577
578 /* get/set capture window */
579 case VIDIOCGWIN:
580 {
581 struct video_window vw;
582 vw.x = 0;
583 vw.y = 0;
584 vw.width = 320;
585 vw.height = 240;
586 vw.chromakey = 0;
587 vw.flags = 0;
588 vw.clips = NULL;
589 vw.clipcount = 0;
590
591 DBG("VIDIOCGWIN\n");
592
593 if (copy_to_user
594 ((void *) arg, (void *) &vw, sizeof (vw)))
595 retval = -EFAULT;
596
597 // I'm not sure what the deal with a capture window is, it is very poorly described
598 // in the doc. So I won't support it now.
599 break;
600 }
601
602 case VIDIOCSWIN:
603 {
604
605 struct video_window vw;
606
607 if (copy_from_user(&vw, arg, sizeof(vw)))
608 {
609 retval = -EFAULT;
610 break;
611 }
612
613 DBG("VIDIOCSWIN %d x %d\n", vw->width, vw->height);
614
615 if ( vw.width != 320 || vw.height != 240 )
616 retval = -EFAULT;
617
618 break;
619 }
620
621 /* mmap interface */
622 case VIDIOCGMBUF:
623 {
624 struct video_mbuf vm;
625 int i;
626
627 DBG("VIDIOCGMBUF\n");
628 memset(&vm, 0, sizeof (vm));
629 vm.size =
630 VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
631 vm.frames = VICAM_FRAMES;
632 for (i = 0; i < VICAM_FRAMES; i++)
633 vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
634
635 if (copy_to_user
636 ((void *) arg, (void *) &vm, sizeof (vm)))
637 retval = -EFAULT;
638
639 break;
640 }
641
642 case VIDIOCMCAPTURE:
643 {
644 struct video_mmap vm;
645 // int video_size;
646
647 if (copy_from_user
648 ((void *) &vm, (void *) arg, sizeof (vm))) {
649 retval = -EFAULT;
650 break;
651 }
652
653 DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
654
655 if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
656 retval = -EINVAL;
657
658 // in theory right here we'd start the image capturing
659 // (fill in a bulk urb and submit it asynchronously)
660 //
661 // Instead we're going to do a total hack job for now and
662 // retrieve the frame in VIDIOCSYNC
663
664 break;
665 }
666
667 case VIDIOCSYNC:
668 {
669 int frame;
670
671 if (copy_from_user((void *) &frame, arg, sizeof (int))) {
672 retval = -EFAULT;
673 break;
674 }
675 DBG("VIDIOCSYNC: %d\n", frame);
676
677 read_frame(cam, frame);
678
679 break;
680 }
681
682 /* pointless to implement overlay with this camera */
683 case VIDIOCCAPTURE:
684 case VIDIOCGFBUF:
685 case VIDIOCSFBUF:
686 case VIDIOCKEY:
687 retval = -EINVAL;
688 break;
689
690 /* tuner interface - we have none */
691 case VIDIOCGTUNER:
692 case VIDIOCSTUNER:
693 case VIDIOCGFREQ:
694 case VIDIOCSFREQ:
695 retval = -EINVAL;
696 break;
697
698 /* audio interface - we have none */
699 case VIDIOCGAUDIO:
700 case VIDIOCSAUDIO:
701 retval = -EINVAL;
702 break;
703 default:
704 retval = -ENOIOCTLCMD;
705 break;
706 }
707
708 up(&cam->busy_lock);
709 return retval;
710 }
711
712 static int
vicam_open(struct video_device * dev,int flags)713 vicam_open(struct video_device *dev, int flags)
714 {
715 struct vicam_camera *cam =
716 (struct vicam_camera *) dev->priv;
717 int intr;
718 DBG("open\n");
719
720 if (!cam) {
721 printk(KERN_ERR
722 "vicam video_device improperly initialized");
723 }
724
725 intr = down_interruptible(&cam->busy_lock);
726 if (intr)
727 return -EINTR;
728
729 if (cam->is_opened) {
730 printk(KERN_INFO
731 "vicam_open called on already opened camera");
732 up(&cam->busy_lock);
733 return -EBUSY;
734 }
735
736 if (!cam->raw_image) {
737 cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
738 if (!cam->raw_image) {
739 up(&cam->busy_lock);
740 return -ENOMEM;
741 }
742 }
743
744 if (!cam->framebuf) {
745 cam->framebuf =
746 usbvideo_rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
747 if (!cam->framebuf) {
748 kfree(cam->raw_image);
749 up(&cam->busy_lock);
750 return -ENOMEM;
751 }
752 }
753 // First upload firmware, then turn the camera on
754
755 if (!cam->is_initialized) {
756 initialize_camera(cam);
757
758 cam->is_initialized = 1;
759 }
760
761 set_camera_power(cam, 1);
762
763 cam->needsDummyRead = 1;
764 cam->is_opened = 1;
765
766 up(&cam->busy_lock);
767
768 return 0;
769 }
770
771 static void
vicam_close(struct video_device * dev)772 vicam_close(struct video_device *dev)
773 {
774 struct vicam_camera *cam = (struct vicam_camera *) dev->priv;
775 DBG("close\n");
776
777
778 if (cam->is_removed) {
779 vicam_purge(cam);
780 } else {
781 set_camera_power(cam, 0);
782 cam->is_opened = 0;
783 }
784 }
785
pin(int x)786 inline int pin(int x)
787 {
788 return((x > 255) ? 255 : ((x < 0) ? 0 : x));
789 }
790
writepixel(char * rgb,int Y,int Cr,int Cb)791 inline void writepixel(char *rgb, int Y, int Cr, int Cb)
792 {
793 Y = 1160 * (Y - 16);
794
795 rgb[2] = pin( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300 );
796 rgb[1] = pin( ( ( Y - ( 392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000 );
797 rgb[0] = pin( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900 );
798 }
799
800 #define DATA_HEADER_SIZE 64
801
802 // --------------------------------------------------------------------------------
803 // vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
804 //
805 // Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
806 // --------------------------------------------------------------------------------
807
vicam_decode_color(char * data,char * rgb)808 void vicam_decode_color( char *data, char *rgb)
809 {
810 int x,y;
811 int Cr, Cb;
812 int sign;
813 int prevX, nextX, prevY, nextY;
814 int skip;
815 unsigned char *src;
816 unsigned char *dst;
817
818 prevY = 512;
819 nextY = 512;
820
821 src = data + DATA_HEADER_SIZE;
822 dst = rgb;
823
824 for(y = 1; y < 241; y += 2)
825 {
826 // even line
827 sign = 1;
828 prevX = 1;
829 nextX = 1;
830
831 skip = 0;
832
833 dst = rgb + (y-1)*320*3;
834
835 for(x = 0; x < 512; x++)
836 {
837 if(x == 512-1)
838 nextX = -1;
839
840 Cr = sign * ((src[prevX] - src[0]) + (src[nextX] - src[0])) >> 1;
841 Cb = sign * ((src[prevY] - src[prevX + prevY]) + (src[prevY] - src[nextX + prevY]) + (src[nextY] - src[prevX + nextY]) + (src[nextY] - src[nextX + nextY])) >> 2;
842
843 writepixel(
844 dst + ((x*5)>>3)*3,
845 src[0] + (sign * (Cr >> 1)),
846 Cr,
847 Cb);
848
849 src++;
850 sign *= -1;
851 prevX = -1;
852 }
853
854 prevY = -512;
855
856 if(y == (242 - 2))
857 nextY = -512;
858
859 // odd line
860 sign = 1;
861 prevX = 1;
862 nextX = 1;
863
864 skip = 0;
865
866 dst = rgb + (y)*320*3;
867
868 for(x = 0; x < 512; x++)
869 {
870 if(x == 512-1)
871 nextX = -1;
872
873 Cr = sign * ((src[prevX + prevY] - src[prevY]) + (src[nextX + prevY] - src[prevY]) + (src[prevX + nextY] - src[nextY]) + (src[nextX + nextY] - src[nextY])) >> 2;
874 Cb = sign * ((src[0] - src[prevX]) + (src[0] - src[nextX])) >> 1;
875
876 writepixel(
877 dst + ((x * 5)>>3)*3,
878 src[0] - (sign * (Cb >> 1)),
879 Cr,
880 Cb);
881
882 src++;
883 sign *= -1;
884 prevX = -1;
885 }
886 }
887 }
888
889 static void
read_frame(struct vicam_camera * cam,int framenum)890 read_frame(struct vicam_camera *cam, int framenum)
891 {
892 unsigned char request[16];
893 int realShutter;
894 int n;
895 int actual_length;
896
897 memset(request, 0, 16);
898 request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
899
900 request[1] = 0; // 512x242 capture
901
902 request[2] = 0x90; // the function of these two bytes
903 request[3] = 0x07; // is not yet understood
904
905 if (cam->shutter_speed > 60) {
906 // Short exposure
907 realShutter =
908 ((-15631900 / cam->shutter_speed) + 260533) / 1000;
909 request[4] = realShutter & 0xFF;
910 request[5] = (realShutter >> 8) & 0xFF;
911 request[6] = 0x03;
912 request[7] = 0x01;
913 } else {
914 // Long exposure
915 realShutter = 15600 / cam->shutter_speed - 1;
916 request[4] = 0;
917 request[5] = 0;
918 request[6] = realShutter & 0xFF;
919 request[7] = realShutter >> 8;
920 }
921
922 // Per John Markus Bj�rndalen, byte at index 8 causes problems if it isn't 0
923 request[8] = 0;
924 // bytes 9-15 do not seem to affect exposure or image quality
925
926 n = send_control_msg(cam->udev, 0x51, 0x80, 0, request, 16);
927
928 if (n < 0) {
929 printk(KERN_ERR
930 " Problem sending frame capture control message");
931 return;
932 }
933
934 n = usb_bulk_msg(cam->udev,
935 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
936 cam->raw_image,
937 512 * 242 + 128, &actual_length, 500);
938
939 if (n < 0) {
940 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
941 n);
942 }
943
944 vicam_decode_color(cam->raw_image,
945 cam->framebuf +
946 framenum * VICAM_MAX_FRAME_SIZE );
947
948 cam->framebuf_size =
949 320 * 240 * VICAM_BYTES_PER_PIXEL;
950 cam->framebuf_read_start = 0;
951
952 return;
953
954 }
955
956 static long
vicam_read(struct video_device * dev,char * buf,unsigned long count,int noblock)957 vicam_read(struct video_device *dev, char *buf,
958 unsigned long count, int noblock)
959 {
960 struct vicam_camera *cam = dev->priv;
961 int intr;
962 DBG("read %d bytes.\n", (int) count);
963
964 if (!buf)
965 return -EINVAL;
966
967 if (!count)
968 return -EINVAL;
969
970 // This is some code that will hopefully allow us to do shell copies from
971 // the /dev/videoX to a file and have it actually work.
972 if (cam->framebuf_size != 0) {
973 if (cam->framebuf_read_start == cam->framebuf_size) {
974 cam->framebuf_size = cam->framebuf_read_start = 0;
975 return 0;
976 } else {
977 if (cam->framebuf_read_start + count <=
978 cam->framebuf_size) {
979 // count does not exceed available bytes
980 if (copy_to_user(buf,
981 (cam->framebuf) +
982 cam->framebuf_read_start, count))
983 return -EFAULT;
984 cam->framebuf_read_start += count;
985 return count;
986 } else {
987 count =
988 cam->framebuf_size -
989 cam->framebuf_read_start;
990 if (copy_to_user(buf,
991 (cam->framebuf) +
992 cam->framebuf_read_start, count))
993 return -EFAULT;
994 cam->framebuf_read_start = cam->framebuf_size;
995 return count;
996 }
997 }
998 }
999
1000 intr = down_interruptible(&cam->busy_lock);
1001 if (intr)
1002 return -EINTR;
1003
1004 if (cam->needsDummyRead) {
1005 read_frame(cam, 0);
1006 cam->needsDummyRead = 0;
1007 }
1008 // read_frame twice because the camera doesn't seem to take the shutter speed for the first one.
1009
1010 read_frame(cam, 0);
1011
1012 if (count > cam->framebuf_size)
1013 count = cam->framebuf_size;
1014
1015 if (copy_to_user(buf, cam->framebuf, count)) {
1016 up(&cam->busy_lock);
1017 return -EFAULT;
1018 }
1019
1020 if (count != cam->framebuf_size)
1021 cam->framebuf_read_start = count;
1022 else
1023 cam->framebuf_size = 0;
1024
1025 up(&cam->busy_lock);
1026
1027 return count;
1028 }
1029
1030 static int
vicam_mmap(struct video_device * dev,const char * adr,unsigned long size)1031 vicam_mmap(struct video_device *dev, const char *adr, unsigned long size)
1032 {
1033 // TODO: allocate the raw frame buffer if necessary
1034 unsigned long start = (unsigned long) adr;
1035 unsigned long page, pos;
1036 struct vicam_camera *cam = dev->priv;
1037
1038 if (!cam)
1039 return -ENODEV;
1040
1041 DBG("vicam_mmap: %ld\n", size);
1042
1043 /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1044 * to the size the application requested for mmap and it was screwing apps up.
1045 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1046 return -EINVAL;
1047 */
1048
1049 /* make this _really_ smp-safe */
1050 if (down_interruptible(&cam->busy_lock))
1051 return -EINTR;
1052
1053 if (!cam->framebuf) { /* we do lazy allocation */
1054 cam->framebuf =
1055 usbvideo_rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
1056 if (!cam->framebuf) {
1057 up(&cam->busy_lock);
1058 return -ENOMEM;
1059 }
1060 }
1061
1062 pos = (unsigned long) (cam->framebuf);
1063 while (size > 0) {
1064 page = usbvideo_kvirt_to_pa(pos);
1065 if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
1066 up(&cam->busy_lock);
1067 return -EAGAIN;
1068 }
1069 start += PAGE_SIZE;
1070 pos += PAGE_SIZE;
1071 if (size > PAGE_SIZE)
1072 size -= PAGE_SIZE;
1073 else
1074 size = 0;
1075 }
1076
1077 up(&cam->busy_lock);
1078
1079 return 0;
1080 }
1081
1082 #ifdef CONFIG_PROC_FS
1083
1084 static struct proc_dir_entry *vicam_proc_root = NULL;
1085
1086 static int
vicam_read_proc(char * page,char ** start,off_t off,int count,int * eof,void * data)1087 vicam_read_proc(char *page, char **start, off_t off,
1088 int count, int *eof, void *data)
1089 {
1090 char *out = page;
1091 int len;
1092 struct vicam_camera *cam = (struct vicam_camera *) data;
1093
1094 out +=
1095 sprintf(out, "Vicam-based WebCam Linux Driver.\n");
1096 out += sprintf(out, "(c) 2002 Joe Burks (jburks@wavicle.org)\n");
1097 out += sprintf(out, "vicam stats:\n");
1098 out += sprintf(out, " Shutter Speed: 1/%d\n", cam->shutter_speed);
1099 out += sprintf(out, " Gain: %d\n", cam->gain);
1100
1101 len = out - page;
1102 len -= off;
1103 if (len < count) {
1104 *eof = 1;
1105 if (len <= 0)
1106 return 0;
1107 } else
1108 len = count;
1109
1110 *start = page + off;
1111 return len;
1112 }
1113
1114 static int
vicam_write_proc(struct file * file,const char * buffer,unsigned long count,void * data)1115 vicam_write_proc(struct file *file, const char *buffer,
1116 unsigned long count, void *data)
1117 {
1118 char *in;
1119 char *start;
1120 struct vicam_camera *cam = (struct vicam_camera *) data;
1121
1122 in = kmalloc(count + 1, GFP_KERNEL);
1123 if (!in)
1124 return -ENOMEM;
1125
1126 in[count] = 0; // I'm not sure buffer is gauranteed to be null terminated
1127 // so I do this to make sure I have a null in there.
1128
1129 strncpy(in, buffer, count);
1130
1131 start = strstr(in, "gain=");
1132 if (start
1133 && (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
1134 cam->gain = simple_strtoul(start + 5, NULL, 10);
1135
1136 start = strstr(in, "shutter=");
1137 if (start
1138 && (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
1139 cam->shutter_speed = simple_strtoul(start + 8, NULL, 10);
1140
1141 kfree(in);
1142 return count;
1143 }
1144
1145 void
vicam_create_proc_root(void)1146 vicam_create_proc_root(void)
1147 {
1148 vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0);
1149
1150 if (vicam_proc_root)
1151 vicam_proc_root->owner = THIS_MODULE;
1152 else
1153 printk(KERN_ERR
1154 "could not create /proc entry for vicam!");
1155 }
1156
1157 void
vicam_destroy_proc_root(void)1158 vicam_destroy_proc_root(void)
1159 {
1160 if (vicam_proc_root)
1161 remove_proc_entry("video/vicam", 0);
1162 }
1163
1164 void
vicam_create_proc_entry(void * ptr)1165 vicam_create_proc_entry(void *ptr)
1166 {
1167 struct vicam_camera *cam = (struct vicam_camera *) ptr;
1168
1169 char name[7];
1170 struct proc_dir_entry *ent;
1171
1172 DBG(KERN_INFO "vicam: creating proc entry\n");
1173
1174 if (!vicam_proc_root || !cam) {
1175 printk(KERN_INFO
1176 "vicam: could not create proc entry, %s pointer is null.\n",
1177 (!cam ? "camera" : "root"));
1178 return;
1179 }
1180
1181 sprintf(name, "video%d", cam->vdev.minor);
1182
1183 ent =
1184 create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
1185 vicam_proc_root);
1186 if (!ent)
1187 return;
1188
1189 ent->data = cam;
1190 ent->read_proc = vicam_read_proc;
1191 ent->write_proc = vicam_write_proc;
1192 ent->size = 512;
1193 cam->proc_entry = ent;
1194 }
1195
1196 void
vicam_destroy_proc_entry(void * ptr)1197 vicam_destroy_proc_entry(void *ptr)
1198 {
1199 struct vicam_camera *cam = (struct vicam_camera *) ptr;
1200 char name[7];
1201
1202 if (!cam || !cam->proc_entry)
1203 return;
1204
1205 sprintf(name, "video%d", cam->vdev.minor);
1206 remove_proc_entry(name, vicam_proc_root);
1207 cam->proc_entry = NULL;
1208
1209 }
1210
1211 #endif
1212
1213 int
vicam_video_init(struct video_device * vdev)1214 vicam_video_init(struct video_device *vdev)
1215 {
1216 // This would normally create the proc entry for this camera
1217 #ifdef CONFIG_PROC_FS
1218 vicam_create_proc_entry(vdev->priv);
1219 #endif
1220 return 0;
1221 }
1222
1223 static long
vicam_write(struct video_device * v,const char * buf,unsigned long count,int nonblock)1224 vicam_write(struct video_device *v, const char *buf, unsigned long count,
1225 int nonblock)
1226 {
1227
1228 return -EINVAL;
1229 }
1230
1231 static struct video_device vicam_template = {
1232 owner:THIS_MODULE,
1233 name:"ViCam-based USB Camera",
1234 type:VID_TYPE_CAPTURE,
1235 hardware:VID_HARDWARE_VICAM,
1236 open:vicam_open,
1237 close:vicam_close,
1238 read:vicam_read,
1239 write:vicam_write,
1240 ioctl:vicam_ioctl,
1241 mmap:vicam_mmap,
1242 initialize:vicam_video_init,
1243 minor:-1,
1244 };
1245
1246 /* table of devices that work with this driver */
1247 static struct usb_device_id vicam_table[] = {
1248 {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1249 {} /* Terminating entry */
1250 };
1251
1252 MODULE_DEVICE_TABLE(usb, vicam_table);
1253
1254 static struct usb_driver vicam_driver = {
1255 name:"vicam",
1256 probe:vicam_probe,
1257 disconnect:vicam_disconnect,
1258 id_table:vicam_table
1259 };
1260
1261 /**
1262 * vicam_probe
1263 *
1264 * Called by the usb core when a new device is connected that it thinks
1265 * this driver might be interested in.
1266 */
1267 static void *
vicam_probe(struct usb_device * dev,unsigned int ifnum,const struct usb_device_id * id)1268 vicam_probe(struct usb_device *dev, unsigned int ifnum,
1269 const struct usb_device_id *id)
1270 {
1271 int nas, bulkEndpoint = 0;
1272 const struct usb_interface_descriptor *interface;
1273 const struct usb_endpoint_descriptor *endpoint;
1274 struct vicam_camera *cam;
1275
1276 /* See if the device offered us matches what we can accept */
1277 if ((dev->descriptor.idVendor != USB_VICAM_VENDOR_ID) ||
1278 (dev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) {
1279 return NULL;
1280 }
1281
1282 printk(KERN_INFO "ViCam based webcam connected\n");
1283
1284 nas = dev->actconfig->interface[ifnum].num_altsetting;
1285 if (nas != 1) {
1286 printk(KERN_WARNING
1287 "Expected only one alternate setting for this camera!\n");
1288 return NULL;
1289 }
1290
1291 interface = &dev->actconfig->interface[ifnum].altsetting[0];
1292 DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1293 ifnum, (unsigned) (interface->bNumEndpoints));
1294 endpoint = &interface->endpoint[0];
1295
1296 if ((endpoint->bEndpointAddress & 0x80) &&
1297 ((endpoint->bmAttributes & 3) == 0x02)) {
1298 /* we found a bulk in endpoint */
1299 bulkEndpoint = endpoint->bEndpointAddress;
1300 } else {
1301 printk(KERN_ERR
1302 "No bulk in endpoint was found ?! (this is bad)\n");
1303 }
1304
1305 if ((cam =
1306 kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1307 printk(KERN_WARNING
1308 "could not allocate kernel memory for vicam_camera struct\n");
1309 return NULL;
1310 }
1311
1312 memset(cam, 0, sizeof (struct vicam_camera));
1313
1314 cam->shutter_speed = 15;
1315
1316 init_MUTEX(&cam->busy_lock);
1317
1318 memcpy(&cam->vdev, &vicam_template,
1319 sizeof (vicam_template));
1320 cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only
1321
1322 cam->udev = dev;
1323 cam->bulkEndpoint = bulkEndpoint;
1324
1325 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1326 kfree(cam);
1327 printk(KERN_WARNING "video_register_device failed\n");
1328 return NULL;
1329 }
1330
1331 printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1332
1333 return cam;
1334 }
1335
1336
1337 static void
vicam_purge(struct vicam_camera * cam)1338 vicam_purge(struct vicam_camera *cam)
1339 {
1340 video_unregister_device(&cam->vdev);
1341
1342 #ifdef CONFIG_PROC_FS
1343 vicam_destroy_proc_entry(cam);
1344 #endif
1345
1346 if (cam->raw_image)
1347 kfree(cam->raw_image);
1348 if (cam->framebuf)
1349 usbvideo_rvfree(cam->framebuf,
1350 VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
1351
1352 kfree(cam);
1353
1354 printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1355 }
1356
1357 static void
vicam_disconnect(struct usb_device * dev,void * ptr)1358 vicam_disconnect(struct usb_device *dev, void *ptr)
1359 {
1360 struct vicam_camera *cam = ptr;
1361
1362 if (cam->is_opened) {
1363 cam->is_removed = 1;
1364 } else {
1365 vicam_purge(cam);
1366 }
1367 }
1368
1369 /*
1370 */
1371 static int __init
usb_vicam_init(void)1372 usb_vicam_init(void)
1373 {
1374 DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1375 #ifdef CONFIG_PROC_FS
1376 vicam_create_proc_root();
1377 #endif
1378 if (usb_register(&vicam_driver) != 0)
1379 printk(KERN_WARNING "usb_register failed!\n");
1380 return 0;
1381 }
1382
1383 static void __exit
usb_vicam_exit(void)1384 usb_vicam_exit(void)
1385 {
1386 DBG(KERN_INFO
1387 "ViCam-based WebCam driver shutdown\n");
1388
1389 usb_deregister(&vicam_driver);
1390 #ifdef CONFIG_PROC_FS
1391 vicam_destroy_proc_root();
1392 #endif
1393 }
1394
1395 module_init(usb_vicam_init);
1396 module_exit(usb_vicam_exit);
1397
1398 MODULE_AUTHOR(DRIVER_AUTHOR);
1399 MODULE_DESCRIPTION(DRIVER_DESC);
1400 MODULE_LICENSE("GPL");
1401