MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / usb / media / vicam.c
blob1e416c1de32df209775a130352718230645256f8
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
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 "usbvideo.h"
47 // #define VICAM_DEBUG
49 #ifdef VICAM_DEBUG
50 #define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
51 #define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
52 #else
53 #define DBG(fmn,args...) do {} while(0)
54 #endif
56 #define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org"
57 #define DRIVER_DESC "ViCam WebCam Driver"
59 /* Define these values to match your device */
60 #define USB_VICAM_VENDOR_ID 0x04c1
61 #define USB_VICAM_PRODUCT_ID 0x009d
63 #define VICAM_BYTES_PER_PIXEL 3
64 #define VICAM_MAX_READ_SIZE (512*242+128)
65 #define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
66 #define VICAM_FRAMES 2
68 #define VICAM_HEADER_SIZE 64
70 #define clamp( x, l, h ) max_t( __typeof__( x ), \
71 ( l ), \
72 min_t( __typeof__( x ), \
73 ( h ), \
74 ( x ) ) )
76 /* Not sure what all the bytes in these char
77 * arrays do, but they're necessary to make
78 * the camera work.
81 static unsigned char setup1[] = {
82 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
83 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
84 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
85 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
86 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
89 static unsigned char setup2[] = {
90 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
91 0x00, 0x00
94 static unsigned char setup3[] = {
95 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
98 static unsigned char setup4[] = {
99 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
100 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
101 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
102 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
103 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
104 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
105 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
106 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
107 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
108 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
109 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
110 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
111 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
112 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
113 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
114 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
115 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
116 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
117 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
118 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
119 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
120 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
121 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
122 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
123 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
124 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
125 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
126 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
127 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
128 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
129 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
130 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
131 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
132 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
133 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
134 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
135 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
136 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
137 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
138 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
139 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
140 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
141 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
142 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
143 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
144 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
145 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
146 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
147 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
148 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
149 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
150 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
151 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
152 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
153 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
154 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
155 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
156 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
157 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
158 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
159 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
160 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
161 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
162 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
163 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
164 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
165 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
166 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
167 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
168 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
169 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
170 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
171 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
172 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
173 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
174 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
175 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
176 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
177 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
178 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
179 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
180 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
181 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
182 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
183 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
184 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
185 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
186 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
187 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
188 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
189 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
190 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
191 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
192 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
193 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
194 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
195 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
196 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
197 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
198 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
199 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
200 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
201 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
202 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
203 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
204 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
205 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
206 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
207 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
208 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
209 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
210 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
211 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
212 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
213 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
214 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
215 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
216 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
217 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
218 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
219 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
220 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
221 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
222 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
223 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
224 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
225 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
226 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
227 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
228 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
229 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
230 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
231 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
232 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
233 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
234 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
235 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
236 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
237 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
238 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
239 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
240 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
241 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
242 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
243 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
244 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
245 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
246 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
247 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
248 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
249 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
250 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
251 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
252 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
253 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
254 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
255 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
256 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
257 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
258 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
259 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
260 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
261 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
262 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
263 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
264 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
265 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
266 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
267 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
268 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
269 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
270 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
271 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
272 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
273 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
274 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
275 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
276 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
277 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
278 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
279 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
280 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
281 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
282 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
283 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
284 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
285 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
286 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
287 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x00, 0x00, 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,
312 static unsigned char setup5[] = {
313 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
314 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
315 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
316 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
317 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
318 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
319 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
320 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
321 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
322 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
323 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
324 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
325 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
326 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
327 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
328 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
329 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
330 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
331 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
332 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
333 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
334 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
335 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
336 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
337 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
338 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
339 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
340 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
341 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
342 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
343 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
344 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
345 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
346 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
347 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
348 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
349 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
350 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
351 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
354 static unsigned long kvirt_to_pa(unsigned long adr)
356 unsigned long kva, ret;
358 kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
359 kva |= adr & (PAGE_SIZE-1); /* restore the offset */
360 ret = __pa(kva);
361 return ret;
364 /* rvmalloc / rvfree copied from usbvideo.c
366 * Not sure why these are not yet non-statics which I can reference through
367 * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime
368 * in the future.
371 static void *rvmalloc(unsigned long size)
373 void *mem;
374 unsigned long adr;
376 size = PAGE_ALIGN(size);
377 mem = vmalloc_32(size);
378 if (!mem)
379 return NULL;
381 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
382 adr = (unsigned long) mem;
383 while (size > 0) {
384 SetPageReserved(vmalloc_to_page((void *)adr));
385 adr += PAGE_SIZE;
386 size -= PAGE_SIZE;
389 return mem;
392 static void rvfree(void *mem, unsigned long size)
394 unsigned long adr;
396 if (!mem)
397 return;
399 adr = (unsigned long) mem;
400 while ((long) size > 0) {
401 ClearPageReserved(vmalloc_to_page((void *)adr));
402 adr += PAGE_SIZE;
403 size -= PAGE_SIZE;
405 vfree(mem);
408 struct vicam_camera {
409 u16 shutter_speed; // capture shutter speed
410 u16 gain; // capture gain
412 u8 *raw_image; // raw data captured from the camera
413 u8 *framebuf; // processed data in RGB24 format
414 u8 *cntrlbuf; // area used to send control msgs
416 struct video_device vdev; // v4l video device
417 struct usb_device *udev; // usb device
419 /* guard against simultaneous accesses to the camera */
420 struct semaphore cam_lock;
422 int is_initialized;
423 u8 open_count;
424 u8 bulkEndpoint;
425 int needsDummyRead;
427 #if defined(CONFIG_VIDEO_PROC_FS)
428 struct proc_dir_entry *proc_dir;
429 #endif
433 static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
434 static void vicam_disconnect(struct usb_interface *intf);
435 static void read_frame(struct vicam_camera *cam, int framenum);
436 static void vicam_decode_color(const u8 *, u8 *);
438 static int __send_control_msg(struct vicam_camera *cam,
439 u8 request,
440 u16 value,
441 u16 index,
442 unsigned char *cp,
443 u16 size)
445 int status;
447 /* cp must be memory that has been allocated by kmalloc */
449 status = usb_control_msg(cam->udev,
450 usb_sndctrlpipe(cam->udev, 0),
451 request,
452 USB_DIR_OUT | USB_TYPE_VENDOR |
453 USB_RECIP_DEVICE, value, index,
454 cp, size, HZ);
456 status = min(status, 0);
458 if (status < 0) {
459 printk(KERN_INFO "Failed sending control message, error %d.\n",
460 status);
463 return status;
466 static int send_control_msg(struct vicam_camera *cam,
467 u8 request,
468 u16 value,
469 u16 index,
470 unsigned char *cp,
471 u16 size)
473 int status = -ENODEV;
474 down(&cam->cam_lock);
475 if (cam->udev) {
476 status = __send_control_msg(cam, request, value,
477 index, cp, size);
479 up(&cam->cam_lock);
480 return status;
482 static int
483 initialize_camera(struct vicam_camera *cam)
485 const struct {
486 u8 *data;
487 u32 size;
488 } firmware[] = {
489 { .data = setup1, .size = sizeof(setup1) },
490 { .data = setup2, .size = sizeof(setup2) },
491 { .data = setup3, .size = sizeof(setup3) },
492 { .data = setup4, .size = sizeof(setup4) },
493 { .data = setup5, .size = sizeof(setup5) },
494 { .data = setup3, .size = sizeof(setup3) },
495 { .data = NULL, .size = 0 }
498 int err, i;
500 for (i = 0, err = 0; firmware[i].data && !err; i++) {
501 memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
503 err = send_control_msg(cam, 0xff, 0, 0,
504 cam->cntrlbuf, firmware[i].size);
507 return err;
510 static int
511 set_camera_power(struct vicam_camera *cam, int state)
513 int status;
515 if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
516 return status;
518 if (state) {
519 send_control_msg(cam, 0x55, 1, 0, NULL, 0);
522 return 0;
525 static int
526 vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
528 void __user *user_arg = (void __user *)arg;
529 struct vicam_camera *cam = file->private_data;
530 int retval = 0;
532 if (!cam)
533 return -ENODEV;
535 switch (ioctlnr) {
536 /* query capabilities */
537 case VIDIOCGCAP:
539 struct video_capability b;
541 DBG("VIDIOCGCAP\n");
542 memset(&b, 0, sizeof(b));
543 strcpy(b.name, "ViCam-based Camera");
544 b.type = VID_TYPE_CAPTURE;
545 b.channels = 1;
546 b.audios = 0;
547 b.maxwidth = 320; /* VIDEOSIZE_CIF */
548 b.maxheight = 240;
549 b.minwidth = 320; /* VIDEOSIZE_48_48 */
550 b.minheight = 240;
552 if (copy_to_user(user_arg, &b, sizeof(b)))
553 retval = -EFAULT;
555 break;
557 /* get/set video source - we are a camera and nothing else */
558 case VIDIOCGCHAN:
560 struct video_channel v;
562 DBG("VIDIOCGCHAN\n");
563 if (copy_from_user(&v, user_arg, sizeof(v))) {
564 retval = -EFAULT;
565 break;
567 if (v.channel != 0) {
568 retval = -EINVAL;
569 break;
572 v.channel = 0;
573 strcpy(v.name, "Camera");
574 v.tuners = 0;
575 v.flags = 0;
576 v.type = VIDEO_TYPE_CAMERA;
577 v.norm = 0;
579 if (copy_to_user(user_arg, &v, sizeof(v)))
580 retval = -EFAULT;
581 break;
584 case VIDIOCSCHAN:
586 int v;
588 if (copy_from_user(&v, user_arg, sizeof(v)))
589 retval = -EFAULT;
590 DBG("VIDIOCSCHAN %d\n", v);
592 if (retval == 0 && v != 0)
593 retval = -EINVAL;
595 break;
598 /* image properties */
599 case VIDIOCGPICT:
601 struct video_picture vp;
602 DBG("VIDIOCGPICT\n");
603 memset(&vp, 0, sizeof (struct video_picture));
604 vp.brightness = cam->gain << 8;
605 vp.depth = 24;
606 vp.palette = VIDEO_PALETTE_RGB24;
607 if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
608 retval = -EFAULT;
609 break;
612 case VIDIOCSPICT:
614 struct video_picture vp;
616 if (copy_from_user(&vp, user_arg, sizeof(vp))) {
617 retval = -EFAULT;
618 break;
621 DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
622 vp.palette);
624 cam->gain = vp.brightness >> 8;
626 if (vp.depth != 24
627 || vp.palette != VIDEO_PALETTE_RGB24)
628 retval = -EINVAL;
630 break;
633 /* get/set capture window */
634 case VIDIOCGWIN:
636 struct video_window vw;
637 vw.x = 0;
638 vw.y = 0;
639 vw.width = 320;
640 vw.height = 240;
641 vw.chromakey = 0;
642 vw.flags = 0;
643 vw.clips = NULL;
644 vw.clipcount = 0;
646 DBG("VIDIOCGWIN\n");
648 if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
649 retval = -EFAULT;
651 // I'm not sure what the deal with a capture window is, it is very poorly described
652 // in the doc. So I won't support it now.
653 break;
656 case VIDIOCSWIN:
659 struct video_window vw;
661 if (copy_from_user(&vw, user_arg, sizeof(vw))) {
662 retval = -EFAULT;
663 break;
666 DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
668 if ( vw.width != 320 || vw.height != 240 )
669 retval = -EFAULT;
671 break;
674 /* mmap interface */
675 case VIDIOCGMBUF:
677 struct video_mbuf vm;
678 int i;
680 DBG("VIDIOCGMBUF\n");
681 memset(&vm, 0, sizeof (vm));
682 vm.size =
683 VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
684 vm.frames = VICAM_FRAMES;
685 for (i = 0; i < VICAM_FRAMES; i++)
686 vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
688 if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
689 retval = -EFAULT;
691 break;
694 case VIDIOCMCAPTURE:
696 struct video_mmap vm;
697 // int video_size;
699 if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
700 retval = -EFAULT;
701 break;
704 DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
706 if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
707 retval = -EINVAL;
709 // in theory right here we'd start the image capturing
710 // (fill in a bulk urb and submit it asynchronously)
712 // Instead we're going to do a total hack job for now and
713 // retrieve the frame in VIDIOCSYNC
715 break;
718 case VIDIOCSYNC:
720 int frame;
722 if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
723 retval = -EFAULT;
724 break;
726 DBG("VIDIOCSYNC: %d\n", frame);
728 read_frame(cam, frame);
729 vicam_decode_color(cam->raw_image,
730 cam->framebuf +
731 frame * VICAM_MAX_FRAME_SIZE );
733 break;
736 /* pointless to implement overlay with this camera */
737 case VIDIOCCAPTURE:
738 case VIDIOCGFBUF:
739 case VIDIOCSFBUF:
740 case VIDIOCKEY:
741 retval = -EINVAL;
742 break;
744 /* tuner interface - we have none */
745 case VIDIOCGTUNER:
746 case VIDIOCSTUNER:
747 case VIDIOCGFREQ:
748 case VIDIOCSFREQ:
749 retval = -EINVAL;
750 break;
752 /* audio interface - we have none */
753 case VIDIOCGAUDIO:
754 case VIDIOCSAUDIO:
755 retval = -EINVAL;
756 break;
757 default:
758 retval = -ENOIOCTLCMD;
759 break;
762 return retval;
765 static int
766 vicam_open(struct inode *inode, struct file *file)
768 struct video_device *dev = video_devdata(file);
769 struct vicam_camera *cam =
770 (struct vicam_camera *) dev->priv;
771 DBG("open\n");
773 if (!cam) {
774 printk(KERN_ERR
775 "vicam video_device improperly initialized");
778 /* the videodev_lock held above us protects us from
779 * simultaneous opens...for now. we probably shouldn't
780 * rely on this fact forever.
783 if (cam->open_count > 0) {
784 printk(KERN_INFO
785 "vicam_open called on already opened camera");
786 return -EBUSY;
789 cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
790 if (!cam->raw_image) {
791 return -ENOMEM;
794 cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
795 if (!cam->framebuf) {
796 kfree(cam->raw_image);
797 return -ENOMEM;
800 cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
801 if (!cam->cntrlbuf) {
802 kfree(cam->raw_image);
803 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
804 return -ENOMEM;
807 // First upload firmware, then turn the camera on
809 if (!cam->is_initialized) {
810 initialize_camera(cam);
812 cam->is_initialized = 1;
815 set_camera_power(cam, 1);
817 cam->needsDummyRead = 1;
818 cam->open_count++;
820 file->private_data = cam;
822 return 0;
825 static int
826 vicam_close(struct inode *inode, struct file *file)
828 struct vicam_camera *cam = file->private_data;
829 int open_count;
830 struct usb_device *udev;
832 DBG("close\n");
834 /* it's not the end of the world if
835 * we fail to turn the camera off.
838 set_camera_power(cam, 0);
840 kfree(cam->raw_image);
841 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
842 kfree(cam->cntrlbuf);
844 down(&cam->cam_lock);
846 cam->open_count--;
847 open_count = cam->open_count;
848 udev = cam->udev;
850 up(&cam->cam_lock);
852 if (!open_count && !udev) {
853 kfree(cam);
856 return 0;
859 static void vicam_decode_color(const u8 *data, u8 *rgb)
861 /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
862 * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
865 int i, prevY, nextY;
867 prevY = 512;
868 nextY = 512;
870 data += VICAM_HEADER_SIZE;
872 for( i = 0; i < 240; i++, data += 512 ) {
873 const int y = ( i * 242 ) / 240;
875 int j, prevX, nextX;
876 int Y, Cr, Cb;
878 if ( y == 242 - 1 ) {
879 nextY = -512;
882 prevX = 1;
883 nextX = 1;
885 for ( j = 0; j < 320; j++, rgb += 3 ) {
886 const int x = ( j * 512 ) / 320;
887 const u8 * const src = &data[x];
889 if ( x == 512 - 1 ) {
890 nextX = -1;
893 Cr = ( src[prevX] - src[0] ) +
894 ( src[nextX] - src[0] );
895 Cr /= 2;
897 Cb = ( src[prevY] - src[prevX + prevY] ) +
898 ( src[prevY] - src[nextX + prevY] ) +
899 ( src[nextY] - src[prevX + nextY] ) +
900 ( src[nextY] - src[nextX + nextY] );
901 Cb /= 4;
903 Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
905 if ( i & 1 ) {
906 int Ct = Cr;
907 Cr = Cb;
908 Cb = Ct;
911 if ( ( x ^ i ) & 1 ) {
912 Cr = -Cr;
913 Cb = -Cb;
916 rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
917 500 ) / 900, 0, 255 );
918 rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
919 ( 813 * Cr ) ) +
920 500 ) / 1000, 0, 255 );
921 rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
922 500 ) / 1300, 0, 255 );
924 prevX = -1;
927 prevY = -512;
931 static void
932 read_frame(struct vicam_camera *cam, int framenum)
934 unsigned char *request = cam->cntrlbuf;
935 int realShutter;
936 int n;
937 int actual_length;
939 if (cam->needsDummyRead) {
940 cam->needsDummyRead = 0;
941 read_frame(cam, framenum);
944 memset(request, 0, 16);
945 request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
947 request[1] = 0; // 512x242 capture
949 request[2] = 0x90; // the function of these two bytes
950 request[3] = 0x07; // is not yet understood
952 if (cam->shutter_speed > 60) {
953 // Short exposure
954 realShutter =
955 ((-15631900 / cam->shutter_speed) + 260533) / 1000;
956 request[4] = realShutter & 0xFF;
957 request[5] = (realShutter >> 8) & 0xFF;
958 request[6] = 0x03;
959 request[7] = 0x01;
960 } else {
961 // Long exposure
962 realShutter = 15600 / cam->shutter_speed - 1;
963 request[4] = 0;
964 request[5] = 0;
965 request[6] = realShutter & 0xFF;
966 request[7] = realShutter >> 8;
969 // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
970 request[8] = 0;
971 // bytes 9-15 do not seem to affect exposure or image quality
973 down(&cam->cam_lock);
975 if (!cam->udev) {
976 goto done;
979 n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
981 if (n < 0) {
982 printk(KERN_ERR
983 " Problem sending frame capture control message");
984 goto done;
987 n = usb_bulk_msg(cam->udev,
988 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
989 cam->raw_image,
990 512 * 242 + 128, &actual_length, HZ*10);
992 if (n < 0) {
993 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
997 done:
998 up(&cam->cam_lock);
1001 static ssize_t
1002 vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
1004 struct vicam_camera *cam = file->private_data;
1006 DBG("read %d bytes.\n", (int) count);
1008 if (*ppos >= VICAM_MAX_FRAME_SIZE) {
1009 *ppos = 0;
1010 return 0;
1013 if (*ppos == 0) {
1014 read_frame(cam, 0);
1015 vicam_decode_color(cam->raw_image,
1016 cam->framebuf +
1017 0 * VICAM_MAX_FRAME_SIZE);
1020 count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
1022 if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
1023 count = -EFAULT;
1024 } else {
1025 *ppos += count;
1028 if (count == VICAM_MAX_FRAME_SIZE) {
1029 *ppos = 0;
1032 return count;
1036 static int
1037 vicam_mmap(struct file *file, struct vm_area_struct *vma)
1039 // TODO: allocate the raw frame buffer if necessary
1040 unsigned long page, pos;
1041 unsigned long start = vma->vm_start;
1042 unsigned long size = vma->vm_end-vma->vm_start;
1043 struct vicam_camera *cam = file->private_data;
1045 if (!cam)
1046 return -ENODEV;
1048 DBG("vicam_mmap: %ld\n", size);
1050 /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1051 * to the size the application requested for mmap and it was screwing apps up.
1052 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1053 return -EINVAL;
1056 pos = (unsigned long)cam->framebuf;
1057 while (size > 0) {
1058 page = kvirt_to_pa(pos);
1059 if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1060 return -EAGAIN;
1062 start += PAGE_SIZE;
1063 pos += PAGE_SIZE;
1064 if (size > PAGE_SIZE)
1065 size -= PAGE_SIZE;
1066 else
1067 size = 0;
1070 return 0;
1073 #if defined(CONFIG_VIDEO_PROC_FS)
1075 static struct proc_dir_entry *vicam_proc_root = NULL;
1077 static int vicam_read_helper(char *page, char **start, off_t off,
1078 int count, int *eof, int value)
1080 char *out = page;
1081 int len;
1083 out += sprintf(out, "%d",value);
1085 len = out - page;
1086 len -= off;
1087 if (len < count) {
1088 *eof = 1;
1089 if (len <= 0)
1090 return 0;
1091 } else
1092 len = count;
1094 *start = page + off;
1095 return len;
1098 static int vicam_read_proc_shutter(char *page, char **start, off_t off,
1099 int count, int *eof, void *data)
1101 return vicam_read_helper(page,start,off,count,eof,
1102 ((struct vicam_camera *)data)->shutter_speed);
1105 static int vicam_read_proc_gain(char *page, char **start, off_t off,
1106 int count, int *eof, void *data)
1108 return vicam_read_helper(page,start,off,count,eof,
1109 ((struct vicam_camera *)data)->gain);
1112 static int
1113 vicam_write_proc_shutter(struct file *file, const char *buffer,
1114 unsigned long count, void *data)
1116 u16 stmp;
1117 char kbuf[8];
1118 struct vicam_camera *cam = (struct vicam_camera *) data;
1120 if (count > 6)
1121 return -EINVAL;
1123 if (copy_from_user(kbuf, buffer, count))
1124 return -EFAULT;
1126 stmp = (u16) simple_strtoul(kbuf, NULL, 10);
1127 if (stmp < 4 || stmp > 32000)
1128 return -EINVAL;
1130 cam->shutter_speed = stmp;
1132 return count;
1135 static int
1136 vicam_write_proc_gain(struct file *file, const char *buffer,
1137 unsigned long count, void *data)
1139 u16 gtmp;
1140 char kbuf[8];
1142 struct vicam_camera *cam = (struct vicam_camera *) data;
1144 if (count > 4)
1145 return -EINVAL;
1147 if (copy_from_user(kbuf, buffer, count))
1148 return -EFAULT;
1150 gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
1151 if (gtmp > 255)
1152 return -EINVAL;
1153 cam->gain = gtmp;
1155 return count;
1158 static void
1159 vicam_create_proc_root(void)
1161 vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0);
1163 if (vicam_proc_root)
1164 vicam_proc_root->owner = THIS_MODULE;
1165 else
1166 printk(KERN_ERR
1167 "could not create /proc entry for vicam!");
1170 static void
1171 vicam_destroy_proc_root(void)
1173 if (vicam_proc_root)
1174 remove_proc_entry("video/vicam", 0);
1177 static void
1178 vicam_create_proc_entry(struct vicam_camera *cam)
1180 char name[64];
1181 struct proc_dir_entry *ent;
1183 DBG(KERN_INFO "vicam: creating proc entry\n");
1185 if (!vicam_proc_root || !cam) {
1186 printk(KERN_INFO
1187 "vicam: could not create proc entry, %s pointer is null.\n",
1188 (!cam ? "camera" : "root"));
1189 return;
1192 sprintf(name, "video%d", cam->vdev.minor);
1194 cam->proc_dir = create_proc_entry(name, S_IFDIR, vicam_proc_root);
1196 if ( !cam->proc_dir )
1197 return; // FIXME: We should probably return an error here
1199 ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
1200 cam->proc_dir);
1201 if (ent) {
1202 ent->data = cam;
1203 ent->read_proc = vicam_read_proc_shutter;
1204 ent->write_proc = vicam_write_proc_shutter;
1205 ent->size = 64;
1208 ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
1209 cam->proc_dir);
1210 if (ent) {
1211 ent->data = cam;
1212 ent->read_proc = vicam_read_proc_gain;
1213 ent->write_proc = vicam_write_proc_gain;
1214 ent->size = 64;
1218 static void
1219 vicam_destroy_proc_entry(void *ptr)
1221 struct vicam_camera *cam = (struct vicam_camera *) ptr;
1222 char name[16];
1224 if ( !cam->proc_dir )
1225 return;
1227 sprintf(name, "video%d", cam->vdev.minor);
1228 remove_proc_entry("shutter", cam->proc_dir);
1229 remove_proc_entry("gain", cam->proc_dir);
1230 remove_proc_entry(name,vicam_proc_root);
1231 cam->proc_dir = NULL;
1235 #else
1236 static inline void vicam_create_proc_root(void) { }
1237 static inline void vicam_destroy_proc_root(void) { }
1238 static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
1239 static inline void vicam_destroy_proc_entry(void *ptr) { }
1240 #endif
1242 static struct file_operations vicam_fops = {
1243 .owner = THIS_MODULE,
1244 .open = vicam_open,
1245 .release = vicam_close,
1246 .read = vicam_read,
1247 .mmap = vicam_mmap,
1248 .ioctl = vicam_ioctl,
1249 .llseek = no_llseek,
1252 static struct video_device vicam_template = {
1253 .owner = THIS_MODULE,
1254 .name = "ViCam-based USB Camera",
1255 .type = VID_TYPE_CAPTURE,
1256 .hardware = VID_HARDWARE_VICAM,
1257 .fops = &vicam_fops,
1258 .minor = -1,
1261 /* table of devices that work with this driver */
1262 static struct usb_device_id vicam_table[] = {
1263 {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1264 {} /* Terminating entry */
1267 MODULE_DEVICE_TABLE(usb, vicam_table);
1269 static struct usb_driver vicam_driver = {
1270 .owner = THIS_MODULE,
1271 .name = "vicam",
1272 .probe = vicam_probe,
1273 .disconnect = vicam_disconnect,
1274 .id_table = vicam_table
1278 * vicam_probe
1279 * @intf: the interface
1280 * @id: the device id
1282 * Called by the usb core when a new device is connected that it thinks
1283 * this driver might be interested in.
1285 static int
1286 vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
1288 struct usb_device *dev = interface_to_usbdev(intf);
1289 int bulkEndpoint = 0;
1290 const struct usb_host_interface *interface;
1291 const struct usb_endpoint_descriptor *endpoint;
1292 struct vicam_camera *cam;
1294 /* See if the device offered us matches what we can accept */
1295 if ((dev->descriptor.idVendor != USB_VICAM_VENDOR_ID) ||
1296 (dev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) {
1297 return -ENODEV;
1300 printk(KERN_INFO "ViCam based webcam connected\n");
1302 interface = intf->cur_altsetting;
1304 DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1305 interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
1306 endpoint = &interface->endpoint[0].desc;
1308 if ((endpoint->bEndpointAddress & 0x80) &&
1309 ((endpoint->bmAttributes & 3) == 0x02)) {
1310 /* we found a bulk in endpoint */
1311 bulkEndpoint = endpoint->bEndpointAddress;
1312 } else {
1313 printk(KERN_ERR
1314 "No bulk in endpoint was found ?! (this is bad)\n");
1317 if ((cam =
1318 kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1319 printk(KERN_WARNING
1320 "could not allocate kernel memory for vicam_camera struct\n");
1321 return -ENOMEM;
1324 memset(cam, 0, sizeof (struct vicam_camera));
1326 cam->shutter_speed = 15;
1328 init_MUTEX(&cam->cam_lock);
1330 memcpy(&cam->vdev, &vicam_template,
1331 sizeof (vicam_template));
1332 cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only
1334 cam->udev = dev;
1335 cam->bulkEndpoint = bulkEndpoint;
1337 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1338 kfree(cam);
1339 printk(KERN_WARNING "video_register_device failed\n");
1340 return -EIO;
1343 vicam_create_proc_entry(cam);
1345 printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1347 usb_set_intfdata (intf, cam);
1349 return 0;
1352 static void
1353 vicam_disconnect(struct usb_interface *intf)
1355 int open_count;
1356 struct vicam_camera *cam = usb_get_intfdata (intf);
1357 usb_set_intfdata (intf, NULL);
1359 /* we must unregister the device before taking its
1360 * cam_lock. This is because the video open call
1361 * holds the same lock as video unregister. if we
1362 * unregister inside of the cam_lock and open also
1363 * uses the cam_lock, we get deadlock.
1366 video_unregister_device(&cam->vdev);
1368 /* stop the camera from being used */
1370 down(&cam->cam_lock);
1372 /* mark the camera as gone */
1374 cam->udev = NULL;
1376 vicam_destroy_proc_entry(cam);
1378 /* the only thing left to do is synchronize with
1379 * our close/release function on who should release
1380 * the camera memory. if there are any users using the
1381 * camera, it's their job. if there are no users,
1382 * it's ours.
1385 open_count = cam->open_count;
1387 up(&cam->cam_lock);
1389 if (!open_count) {
1390 kfree(cam);
1393 printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1398 static int __init
1399 usb_vicam_init(void)
1401 int retval;
1402 DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1403 vicam_create_proc_root();
1404 retval = usb_register(&vicam_driver);
1405 if (retval)
1406 printk(KERN_WARNING "usb_register failed!\n");
1407 return retval;
1410 static void __exit
1411 usb_vicam_exit(void)
1413 DBG(KERN_INFO
1414 "ViCam-based WebCam driver shutdown\n");
1416 usb_deregister(&vicam_driver);
1417 vicam_destroy_proc_root();
1420 module_init(usb_vicam_init);
1421 module_exit(usb_vicam_exit);
1423 MODULE_AUTHOR(DRIVER_AUTHOR);
1424 MODULE_DESCRIPTION(DRIVER_DESC);
1425 MODULE_LICENSE("GPL");