RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / drivers / media / video / usbvideo / vicam.c
blob40ee5e538d8faa65430939828dc0f15185e2f183
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)
9 * Supports 3COM HomeConnect PC Digital WebCam
10 * Supports Compro PS39U WebCam
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * This source code is based heavily on the CPiA webcam driver which was
27 * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
29 * Portions of this code were also copied from usbvideo.c
31 * Special thanks to the whole team at Sourceforge for help making
32 * this driver become a reality. Notably:
33 * Andy Armstrong who reverse engineered the color encoding and
34 * Pavel Machek and Chris Cheney who worked on reverse engineering the
35 * camera controls and wrote the first generation driver.
38 #include <linux/kernel.h>
39 #include <linux/module.h>
40 #include <linux/init.h>
41 #include <linux/videodev.h>
42 #include <linux/usb.h>
43 #include <linux/vmalloc.h>
44 #include <linux/slab.h>
45 #include <linux/proc_fs.h>
46 #include <linux/mutex.h>
47 #include "usbvideo.h"
49 // #define VICAM_DEBUG
51 #ifdef VICAM_DEBUG
52 #define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
53 #define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
54 #else
55 #define DBG(fmn,args...) do {} while(0)
56 #endif
58 #define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org"
59 #define DRIVER_DESC "ViCam WebCam Driver"
61 /* Define these values to match your device */
62 #define USB_VICAM_VENDOR_ID 0x04c1
63 #define USB_VICAM_PRODUCT_ID 0x009d
64 #define USB_COMPRO_VENDOR_ID 0x0602
65 #define USB_COMPRO_PRODUCT_ID 0x1001
67 #define VICAM_BYTES_PER_PIXEL 3
68 #define VICAM_MAX_READ_SIZE (512*242+128)
69 #define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
70 #define VICAM_FRAMES 2
72 #define VICAM_HEADER_SIZE 64
74 #define clamp( x, l, h ) max_t( __typeof__( x ), \
75 ( l ), \
76 min_t( __typeof__( x ), \
77 ( h ), \
78 ( x ) ) )
80 /* Not sure what all the bytes in these char
81 * arrays do, but they're necessary to make
82 * the camera work.
85 static unsigned char setup1[] = {
86 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
87 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
88 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
89 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
90 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
93 static unsigned char setup2[] = {
94 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
95 0x00, 0x00
98 static unsigned char setup3[] = {
99 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
102 static unsigned char setup4[] = {
103 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
104 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
105 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
106 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
107 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
108 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
109 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
110 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
111 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
112 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
113 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
114 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
115 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
116 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
117 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
118 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
119 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
120 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
121 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
122 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
123 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
124 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
125 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
126 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
127 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
128 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
129 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
130 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
131 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
132 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
133 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
134 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
135 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
136 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
137 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
138 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
139 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
140 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
141 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
142 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
143 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
144 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
145 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
146 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
147 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
148 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
149 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
150 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
151 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
152 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
153 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
154 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
155 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
156 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
157 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
158 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
159 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
160 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
161 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
162 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
163 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
164 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
165 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
166 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
167 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
168 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
169 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
170 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
171 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
172 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
173 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
174 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
175 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
176 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
177 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
178 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
179 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
180 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
181 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
182 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
183 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
184 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
185 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
186 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
187 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
188 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
189 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
190 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
191 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
192 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
193 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
194 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
195 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
196 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
197 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
198 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
199 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
200 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
201 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
202 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
203 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
204 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
205 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
206 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
207 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
208 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
209 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
210 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
211 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
212 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
213 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
214 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
215 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
216 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
217 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
218 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
219 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
220 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
221 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
222 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
223 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
224 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
225 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
226 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
227 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
228 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
229 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
230 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
231 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
232 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
233 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
234 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
235 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
236 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
237 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
238 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
239 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
240 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
241 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
242 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
243 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
244 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
245 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
246 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
247 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
248 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
249 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
250 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
251 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
252 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
253 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
254 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
255 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
256 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
257 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
258 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
259 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
260 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
261 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
262 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
263 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
264 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
265 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
266 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
267 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
268 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
269 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
270 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
271 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
272 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
273 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
274 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
275 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
276 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
277 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
278 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
279 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
280 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
281 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
282 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
283 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
284 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
285 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
286 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
287 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
288 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
289 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
290 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
291 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 static unsigned char setup5[] = {
317 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
318 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
319 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
320 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
321 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
322 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
323 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
324 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
325 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
326 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
327 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
328 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
329 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
330 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
331 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
332 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
333 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
334 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
335 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
336 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
337 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
338 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
339 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
340 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
341 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
342 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
343 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
344 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
345 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
346 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
347 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
348 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
349 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
350 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
351 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
352 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
353 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
354 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
355 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
358 /* rvmalloc / rvfree copied from usbvideo.c
360 * Not sure why these are not yet non-statics which I can reference through
361 * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime
362 * in the future.
365 static void *rvmalloc(unsigned long size)
367 void *mem;
368 unsigned long adr;
370 size = PAGE_ALIGN(size);
371 mem = vmalloc_32(size);
372 if (!mem)
373 return NULL;
375 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
376 adr = (unsigned long) mem;
377 while (size > 0) {
378 SetPageReserved(vmalloc_to_page((void *)adr));
379 adr += PAGE_SIZE;
380 size -= PAGE_SIZE;
383 return mem;
386 static void rvfree(void *mem, unsigned long size)
388 unsigned long adr;
390 if (!mem)
391 return;
393 adr = (unsigned long) mem;
394 while ((long) size > 0) {
395 ClearPageReserved(vmalloc_to_page((void *)adr));
396 adr += PAGE_SIZE;
397 size -= PAGE_SIZE;
399 vfree(mem);
402 struct vicam_camera {
403 u16 shutter_speed; // capture shutter speed
404 u16 gain; // capture gain
406 u8 *raw_image; // raw data captured from the camera
407 u8 *framebuf; // processed data in RGB24 format
408 u8 *cntrlbuf; // area used to send control msgs
410 struct video_device vdev; // v4l video device
411 struct usb_device *udev; // usb device
413 /* guard against simultaneous accesses to the camera */
414 struct mutex cam_lock;
416 int is_initialized;
417 u8 open_count;
418 u8 bulkEndpoint;
419 int needsDummyRead;
421 #if defined(CONFIG_VIDEO_PROC_FS)
422 struct proc_dir_entry *proc_dir;
423 #endif
427 static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
428 static void vicam_disconnect(struct usb_interface *intf);
429 static void read_frame(struct vicam_camera *cam, int framenum);
430 static void vicam_decode_color(const u8 *, u8 *);
432 static int __send_control_msg(struct vicam_camera *cam,
433 u8 request,
434 u16 value,
435 u16 index,
436 unsigned char *cp,
437 u16 size)
439 int status;
441 /* cp must be memory that has been allocated by kmalloc */
443 status = usb_control_msg(cam->udev,
444 usb_sndctrlpipe(cam->udev, 0),
445 request,
446 USB_DIR_OUT | USB_TYPE_VENDOR |
447 USB_RECIP_DEVICE, value, index,
448 cp, size, 1000);
450 status = min(status, 0);
452 if (status < 0) {
453 printk(KERN_INFO "Failed sending control message, error %d.\n",
454 status);
457 return status;
460 static int send_control_msg(struct vicam_camera *cam,
461 u8 request,
462 u16 value,
463 u16 index,
464 unsigned char *cp,
465 u16 size)
467 int status = -ENODEV;
468 mutex_lock(&cam->cam_lock);
469 if (cam->udev) {
470 status = __send_control_msg(cam, request, value,
471 index, cp, size);
473 mutex_unlock(&cam->cam_lock);
474 return status;
476 static int
477 initialize_camera(struct vicam_camera *cam)
479 const struct {
480 u8 *data;
481 u32 size;
482 } firmware[] = {
483 { .data = setup1, .size = sizeof(setup1) },
484 { .data = setup2, .size = sizeof(setup2) },
485 { .data = setup3, .size = sizeof(setup3) },
486 { .data = setup4, .size = sizeof(setup4) },
487 { .data = setup5, .size = sizeof(setup5) },
488 { .data = setup3, .size = sizeof(setup3) },
489 { .data = NULL, .size = 0 }
492 int err, i;
494 for (i = 0, err = 0; firmware[i].data && !err; i++) {
495 memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
497 err = send_control_msg(cam, 0xff, 0, 0,
498 cam->cntrlbuf, firmware[i].size);
501 return err;
504 static int
505 set_camera_power(struct vicam_camera *cam, int state)
507 int status;
509 if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
510 return status;
512 if (state) {
513 send_control_msg(cam, 0x55, 1, 0, NULL, 0);
516 return 0;
519 static int
520 vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
522 void __user *user_arg = (void __user *)arg;
523 struct vicam_camera *cam = file->private_data;
524 int retval = 0;
526 if (!cam)
527 return -ENODEV;
529 switch (ioctlnr) {
530 /* query capabilities */
531 case VIDIOCGCAP:
533 struct video_capability b;
535 DBG("VIDIOCGCAP\n");
536 memset(&b, 0, sizeof(b));
537 strcpy(b.name, "ViCam-based Camera");
538 b.type = VID_TYPE_CAPTURE;
539 b.channels = 1;
540 b.audios = 0;
541 b.maxwidth = 320; /* VIDEOSIZE_CIF */
542 b.maxheight = 240;
543 b.minwidth = 320; /* VIDEOSIZE_48_48 */
544 b.minheight = 240;
546 if (copy_to_user(user_arg, &b, sizeof(b)))
547 retval = -EFAULT;
549 break;
551 /* get/set video source - we are a camera and nothing else */
552 case VIDIOCGCHAN:
554 struct video_channel v;
556 DBG("VIDIOCGCHAN\n");
557 if (copy_from_user(&v, user_arg, sizeof(v))) {
558 retval = -EFAULT;
559 break;
561 if (v.channel != 0) {
562 retval = -EINVAL;
563 break;
566 v.channel = 0;
567 strcpy(v.name, "Camera");
568 v.tuners = 0;
569 v.flags = 0;
570 v.type = VIDEO_TYPE_CAMERA;
571 v.norm = 0;
573 if (copy_to_user(user_arg, &v, sizeof(v)))
574 retval = -EFAULT;
575 break;
578 case VIDIOCSCHAN:
580 int v;
582 if (copy_from_user(&v, user_arg, sizeof(v)))
583 retval = -EFAULT;
584 DBG("VIDIOCSCHAN %d\n", v);
586 if (retval == 0 && v != 0)
587 retval = -EINVAL;
589 break;
592 /* image properties */
593 case VIDIOCGPICT:
595 struct video_picture vp;
596 DBG("VIDIOCGPICT\n");
597 memset(&vp, 0, sizeof (struct video_picture));
598 vp.brightness = cam->gain << 8;
599 vp.depth = 24;
600 vp.palette = VIDEO_PALETTE_RGB24;
601 if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
602 retval = -EFAULT;
603 break;
606 case VIDIOCSPICT:
608 struct video_picture vp;
610 if (copy_from_user(&vp, user_arg, sizeof(vp))) {
611 retval = -EFAULT;
612 break;
615 DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
616 vp.palette);
618 cam->gain = vp.brightness >> 8;
620 if (vp.depth != 24
621 || vp.palette != VIDEO_PALETTE_RGB24)
622 retval = -EINVAL;
624 break;
627 /* get/set capture window */
628 case VIDIOCGWIN:
630 struct video_window vw;
631 vw.x = 0;
632 vw.y = 0;
633 vw.width = 320;
634 vw.height = 240;
635 vw.chromakey = 0;
636 vw.flags = 0;
637 vw.clips = NULL;
638 vw.clipcount = 0;
640 DBG("VIDIOCGWIN\n");
642 if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
643 retval = -EFAULT;
645 // I'm not sure what the deal with a capture window is, it is very poorly described
646 // in the doc. So I won't support it now.
647 break;
650 case VIDIOCSWIN:
653 struct video_window vw;
655 if (copy_from_user(&vw, user_arg, sizeof(vw))) {
656 retval = -EFAULT;
657 break;
660 DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
662 if ( vw.width != 320 || vw.height != 240 )
663 retval = -EFAULT;
665 break;
668 /* mmap interface */
669 case VIDIOCGMBUF:
671 struct video_mbuf vm;
672 int i;
674 DBG("VIDIOCGMBUF\n");
675 memset(&vm, 0, sizeof (vm));
676 vm.size =
677 VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
678 vm.frames = VICAM_FRAMES;
679 for (i = 0; i < VICAM_FRAMES; i++)
680 vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
682 if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
683 retval = -EFAULT;
685 break;
688 case VIDIOCMCAPTURE:
690 struct video_mmap vm;
691 // int video_size;
693 if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
694 retval = -EFAULT;
695 break;
698 DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
700 if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
701 retval = -EINVAL;
703 // in theory right here we'd start the image capturing
704 // (fill in a bulk urb and submit it asynchronously)
706 // Instead we're going to do a total hack job for now and
707 // retrieve the frame in VIDIOCSYNC
709 break;
712 case VIDIOCSYNC:
714 int frame;
716 if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
717 retval = -EFAULT;
718 break;
720 DBG("VIDIOCSYNC: %d\n", frame);
722 read_frame(cam, frame);
723 vicam_decode_color(cam->raw_image,
724 cam->framebuf +
725 frame * VICAM_MAX_FRAME_SIZE );
727 break;
730 /* pointless to implement overlay with this camera */
731 case VIDIOCCAPTURE:
732 case VIDIOCGFBUF:
733 case VIDIOCSFBUF:
734 case VIDIOCKEY:
735 retval = -EINVAL;
736 break;
738 /* tuner interface - we have none */
739 case VIDIOCGTUNER:
740 case VIDIOCSTUNER:
741 case VIDIOCGFREQ:
742 case VIDIOCSFREQ:
743 retval = -EINVAL;
744 break;
746 /* audio interface - we have none */
747 case VIDIOCGAUDIO:
748 case VIDIOCSAUDIO:
749 retval = -EINVAL;
750 break;
751 default:
752 retval = -ENOIOCTLCMD;
753 break;
756 return retval;
759 static int
760 vicam_open(struct inode *inode, struct file *file)
762 struct video_device *dev = video_devdata(file);
763 struct vicam_camera *cam =
764 (struct vicam_camera *) dev->priv;
765 DBG("open\n");
767 if (!cam) {
768 printk(KERN_ERR
769 "vicam video_device improperly initialized");
770 return -EINVAL;
773 /* the videodev_lock held above us protects us from
774 * simultaneous opens...for now. we probably shouldn't
775 * rely on this fact forever.
778 if (cam->open_count > 0) {
779 printk(KERN_INFO
780 "vicam_open called on already opened camera");
781 return -EBUSY;
784 cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
785 if (!cam->raw_image) {
786 return -ENOMEM;
789 cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
790 if (!cam->framebuf) {
791 kfree(cam->raw_image);
792 return -ENOMEM;
795 cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
796 if (!cam->cntrlbuf) {
797 kfree(cam->raw_image);
798 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
799 return -ENOMEM;
802 // First upload firmware, then turn the camera on
804 if (!cam->is_initialized) {
805 initialize_camera(cam);
807 cam->is_initialized = 1;
810 set_camera_power(cam, 1);
812 cam->needsDummyRead = 1;
813 cam->open_count++;
815 file->private_data = cam;
817 return 0;
820 static int
821 vicam_close(struct inode *inode, struct file *file)
823 struct vicam_camera *cam = file->private_data;
824 int open_count;
825 struct usb_device *udev;
827 DBG("close\n");
829 /* it's not the end of the world if
830 * we fail to turn the camera off.
833 set_camera_power(cam, 0);
835 kfree(cam->raw_image);
836 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
837 kfree(cam->cntrlbuf);
839 mutex_lock(&cam->cam_lock);
841 cam->open_count--;
842 open_count = cam->open_count;
843 udev = cam->udev;
845 mutex_unlock(&cam->cam_lock);
847 if (!open_count && !udev) {
848 kfree(cam);
851 return 0;
854 static void vicam_decode_color(const u8 *data, u8 *rgb)
856 /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
857 * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
860 int i, prevY, nextY;
862 prevY = 512;
863 nextY = 512;
865 data += VICAM_HEADER_SIZE;
867 for( i = 0; i < 240; i++, data += 512 ) {
868 const int y = ( i * 242 ) / 240;
870 int j, prevX, nextX;
871 int Y, Cr, Cb;
873 if ( y == 242 - 1 ) {
874 nextY = -512;
877 prevX = 1;
878 nextX = 1;
880 for ( j = 0; j < 320; j++, rgb += 3 ) {
881 const int x = ( j * 512 ) / 320;
882 const u8 * const src = &data[x];
884 if ( x == 512 - 1 ) {
885 nextX = -1;
888 Cr = ( src[prevX] - src[0] ) +
889 ( src[nextX] - src[0] );
890 Cr /= 2;
892 Cb = ( src[prevY] - src[prevX + prevY] ) +
893 ( src[prevY] - src[nextX + prevY] ) +
894 ( src[nextY] - src[prevX + nextY] ) +
895 ( src[nextY] - src[nextX + nextY] );
896 Cb /= 4;
898 Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
900 if ( i & 1 ) {
901 int Ct = Cr;
902 Cr = Cb;
903 Cb = Ct;
906 if ( ( x ^ i ) & 1 ) {
907 Cr = -Cr;
908 Cb = -Cb;
911 rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
912 500 ) / 900, 0, 255 );
913 rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
914 ( 813 * Cr ) ) +
915 500 ) / 1000, 0, 255 );
916 rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
917 500 ) / 1300, 0, 255 );
919 prevX = -1;
922 prevY = -512;
926 static void
927 read_frame(struct vicam_camera *cam, int framenum)
929 unsigned char *request = cam->cntrlbuf;
930 int realShutter;
931 int n;
932 int actual_length;
934 if (cam->needsDummyRead) {
935 cam->needsDummyRead = 0;
936 read_frame(cam, framenum);
939 memset(request, 0, 16);
940 request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
942 request[1] = 0; // 512x242 capture
944 request[2] = 0x90; // the function of these two bytes
945 request[3] = 0x07; // is not yet understood
947 if (cam->shutter_speed > 60) {
948 // Short exposure
949 realShutter =
950 ((-15631900 / cam->shutter_speed) + 260533) / 1000;
951 request[4] = realShutter & 0xFF;
952 request[5] = (realShutter >> 8) & 0xFF;
953 request[6] = 0x03;
954 request[7] = 0x01;
955 } else {
956 // Long exposure
957 realShutter = 15600 / cam->shutter_speed - 1;
958 request[4] = 0;
959 request[5] = 0;
960 request[6] = realShutter & 0xFF;
961 request[7] = realShutter >> 8;
964 // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
965 request[8] = 0;
966 // bytes 9-15 do not seem to affect exposure or image quality
968 mutex_lock(&cam->cam_lock);
970 if (!cam->udev) {
971 goto done;
974 n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
976 if (n < 0) {
977 printk(KERN_ERR
978 " Problem sending frame capture control message");
979 goto done;
982 n = usb_bulk_msg(cam->udev,
983 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
984 cam->raw_image,
985 512 * 242 + 128, &actual_length, 10000);
987 if (n < 0) {
988 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
992 done:
993 mutex_unlock(&cam->cam_lock);
996 static ssize_t
997 vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
999 struct vicam_camera *cam = file->private_data;
1001 DBG("read %d bytes.\n", (int) count);
1003 if (*ppos >= VICAM_MAX_FRAME_SIZE) {
1004 *ppos = 0;
1005 return 0;
1008 if (*ppos == 0) {
1009 read_frame(cam, 0);
1010 vicam_decode_color(cam->raw_image,
1011 cam->framebuf +
1012 0 * VICAM_MAX_FRAME_SIZE);
1015 count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
1017 if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
1018 count = -EFAULT;
1019 } else {
1020 *ppos += count;
1023 if (count == VICAM_MAX_FRAME_SIZE) {
1024 *ppos = 0;
1027 return count;
1031 static int
1032 vicam_mmap(struct file *file, struct vm_area_struct *vma)
1034 // TODO: allocate the raw frame buffer if necessary
1035 unsigned long page, pos;
1036 unsigned long start = vma->vm_start;
1037 unsigned long size = vma->vm_end-vma->vm_start;
1038 struct vicam_camera *cam = file->private_data;
1040 if (!cam)
1041 return -ENODEV;
1043 DBG("vicam_mmap: %ld\n", size);
1045 /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1046 * to the size the application requested for mmap and it was screwing apps up.
1047 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1048 return -EINVAL;
1051 pos = (unsigned long)cam->framebuf;
1052 while (size > 0) {
1053 page = vmalloc_to_pfn((void *)pos);
1054 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1055 return -EAGAIN;
1057 start += PAGE_SIZE;
1058 pos += PAGE_SIZE;
1059 if (size > PAGE_SIZE)
1060 size -= PAGE_SIZE;
1061 else
1062 size = 0;
1065 return 0;
1068 #if defined(CONFIG_VIDEO_PROC_FS)
1070 static struct proc_dir_entry *vicam_proc_root = NULL;
1072 static int vicam_read_helper(char *page, char **start, off_t off,
1073 int count, int *eof, int value)
1075 char *out = page;
1076 int len;
1078 out += sprintf(out, "%d",value);
1080 len = out - page;
1081 len -= off;
1082 if (len < count) {
1083 *eof = 1;
1084 if (len <= 0)
1085 return 0;
1086 } else
1087 len = count;
1089 *start = page + off;
1090 return len;
1093 static int vicam_read_proc_shutter(char *page, char **start, off_t off,
1094 int count, int *eof, void *data)
1096 return vicam_read_helper(page,start,off,count,eof,
1097 ((struct vicam_camera *)data)->shutter_speed);
1100 static int vicam_read_proc_gain(char *page, char **start, off_t off,
1101 int count, int *eof, void *data)
1103 return vicam_read_helper(page,start,off,count,eof,
1104 ((struct vicam_camera *)data)->gain);
1107 static int
1108 vicam_write_proc_shutter(struct file *file, const char *buffer,
1109 unsigned long count, void *data)
1111 u16 stmp;
1112 char kbuf[8];
1113 struct vicam_camera *cam = (struct vicam_camera *) data;
1115 if (count > 6)
1116 return -EINVAL;
1118 if (copy_from_user(kbuf, buffer, count))
1119 return -EFAULT;
1121 stmp = (u16) simple_strtoul(kbuf, NULL, 10);
1122 if (stmp < 4 || stmp > 32000)
1123 return -EINVAL;
1125 cam->shutter_speed = stmp;
1127 return count;
1130 static int
1131 vicam_write_proc_gain(struct file *file, const char *buffer,
1132 unsigned long count, void *data)
1134 u16 gtmp;
1135 char kbuf[8];
1137 struct vicam_camera *cam = (struct vicam_camera *) data;
1139 if (count > 4)
1140 return -EINVAL;
1142 if (copy_from_user(kbuf, buffer, count))
1143 return -EFAULT;
1145 gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
1146 if (gtmp > 255)
1147 return -EINVAL;
1148 cam->gain = gtmp;
1150 return count;
1153 static void
1154 vicam_create_proc_root(void)
1156 vicam_proc_root = proc_mkdir("video/vicam", NULL);
1158 if (vicam_proc_root)
1159 vicam_proc_root->owner = THIS_MODULE;
1160 else
1161 printk(KERN_ERR
1162 "could not create /proc entry for vicam!");
1165 static void
1166 vicam_destroy_proc_root(void)
1168 if (vicam_proc_root)
1169 remove_proc_entry("video/vicam", 0);
1172 static void
1173 vicam_create_proc_entry(struct vicam_camera *cam)
1175 char name[64];
1176 struct proc_dir_entry *ent;
1178 DBG(KERN_INFO "vicam: creating proc entry\n");
1180 if (!vicam_proc_root || !cam) {
1181 printk(KERN_INFO
1182 "vicam: could not create proc entry, %s pointer is null.\n",
1183 (!cam ? "camera" : "root"));
1184 return;
1187 sprintf(name, "video%d", cam->vdev.minor);
1189 cam->proc_dir = proc_mkdir(name, vicam_proc_root);
1191 if ( !cam->proc_dir )
1192 return; // FIXME: We should probably return an error here
1194 ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
1195 cam->proc_dir);
1196 if (ent) {
1197 ent->data = cam;
1198 ent->read_proc = vicam_read_proc_shutter;
1199 ent->write_proc = vicam_write_proc_shutter;
1200 ent->size = 64;
1203 ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
1204 cam->proc_dir);
1205 if (ent) {
1206 ent->data = cam;
1207 ent->read_proc = vicam_read_proc_gain;
1208 ent->write_proc = vicam_write_proc_gain;
1209 ent->size = 64;
1213 static void
1214 vicam_destroy_proc_entry(void *ptr)
1216 struct vicam_camera *cam = (struct vicam_camera *) ptr;
1217 char name[16];
1219 if ( !cam->proc_dir )
1220 return;
1222 sprintf(name, "video%d", cam->vdev.minor);
1223 remove_proc_entry("shutter", cam->proc_dir);
1224 remove_proc_entry("gain", cam->proc_dir);
1225 remove_proc_entry(name,vicam_proc_root);
1226 cam->proc_dir = NULL;
1230 #else
1231 static inline void vicam_create_proc_root(void) { }
1232 static inline void vicam_destroy_proc_root(void) { }
1233 static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
1234 static inline void vicam_destroy_proc_entry(void *ptr) { }
1235 #endif
1237 static const struct file_operations vicam_fops = {
1238 .owner = THIS_MODULE,
1239 .open = vicam_open,
1240 .release = vicam_close,
1241 .read = vicam_read,
1242 .mmap = vicam_mmap,
1243 .ioctl = vicam_ioctl,
1244 .compat_ioctl = v4l_compat_ioctl32,
1245 .llseek = no_llseek,
1248 static struct video_device vicam_template = {
1249 .owner = THIS_MODULE,
1250 .name = "ViCam-based USB Camera",
1251 .type = VID_TYPE_CAPTURE,
1252 .hardware = VID_HARDWARE_VICAM,
1253 .fops = &vicam_fops,
1254 .minor = -1,
1257 /* table of devices that work with this driver */
1258 static struct usb_device_id vicam_table[] = {
1259 {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1260 {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
1261 {} /* Terminating entry */
1264 MODULE_DEVICE_TABLE(usb, vicam_table);
1266 static struct usb_driver vicam_driver = {
1267 .name = "vicam",
1268 .probe = vicam_probe,
1269 .disconnect = vicam_disconnect,
1270 .id_table = vicam_table
1274 * vicam_probe
1275 * @intf: the interface
1276 * @id: the device id
1278 * Called by the usb core when a new device is connected that it thinks
1279 * this driver might be interested in.
1281 static int
1282 vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
1284 struct usb_device *dev = interface_to_usbdev(intf);
1285 int bulkEndpoint = 0;
1286 const struct usb_host_interface *interface;
1287 const struct usb_endpoint_descriptor *endpoint;
1288 struct vicam_camera *cam;
1290 printk(KERN_INFO "ViCam based webcam connected\n");
1292 interface = intf->cur_altsetting;
1294 DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1295 interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
1296 endpoint = &interface->endpoint[0].desc;
1298 if ((endpoint->bEndpointAddress & 0x80) &&
1299 ((endpoint->bmAttributes & 3) == 0x02)) {
1300 /* we found a bulk in endpoint */
1301 bulkEndpoint = endpoint->bEndpointAddress;
1302 } else {
1303 printk(KERN_ERR
1304 "No bulk in endpoint was found ?! (this is bad)\n");
1307 if ((cam =
1308 kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1309 printk(KERN_WARNING
1310 "could not allocate kernel memory for vicam_camera struct\n");
1311 return -ENOMEM;
1315 cam->shutter_speed = 15;
1317 mutex_init(&cam->cam_lock);
1319 memcpy(&cam->vdev, &vicam_template,
1320 sizeof (vicam_template));
1321 cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only
1323 cam->udev = dev;
1324 cam->bulkEndpoint = bulkEndpoint;
1326 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1327 kfree(cam);
1328 printk(KERN_WARNING "video_register_device failed\n");
1329 return -EIO;
1332 vicam_create_proc_entry(cam);
1334 printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1336 usb_set_intfdata (intf, cam);
1338 return 0;
1341 static void
1342 vicam_disconnect(struct usb_interface *intf)
1344 int open_count;
1345 struct vicam_camera *cam = usb_get_intfdata (intf);
1346 usb_set_intfdata (intf, NULL);
1348 /* we must unregister the device before taking its
1349 * cam_lock. This is because the video open call
1350 * holds the same lock as video unregister. if we
1351 * unregister inside of the cam_lock and open also
1352 * uses the cam_lock, we get deadlock.
1355 video_unregister_device(&cam->vdev);
1357 /* stop the camera from being used */
1359 mutex_lock(&cam->cam_lock);
1361 /* mark the camera as gone */
1363 cam->udev = NULL;
1365 vicam_destroy_proc_entry(cam);
1367 /* the only thing left to do is synchronize with
1368 * our close/release function on who should release
1369 * the camera memory. if there are any users using the
1370 * camera, it's their job. if there are no users,
1371 * it's ours.
1374 open_count = cam->open_count;
1376 mutex_unlock(&cam->cam_lock);
1378 if (!open_count) {
1379 kfree(cam);
1382 printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1387 static int __init
1388 usb_vicam_init(void)
1390 int retval;
1391 DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1392 vicam_create_proc_root();
1393 retval = usb_register(&vicam_driver);
1394 if (retval)
1395 printk(KERN_WARNING "usb_register failed!\n");
1396 return retval;
1399 static void __exit
1400 usb_vicam_exit(void)
1402 DBG(KERN_INFO
1403 "ViCam-based WebCam driver shutdown\n");
1405 usb_deregister(&vicam_driver);
1406 vicam_destroy_proc_root();
1409 module_init(usb_vicam_init);
1410 module_exit(usb_vicam_exit);
1412 MODULE_AUTHOR(DRIVER_AUTHOR);
1413 MODULE_DESCRIPTION(DRIVER_DESC);
1414 MODULE_LICENSE("GPL");