aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/media/vicam.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/usb/media/vicam.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/usb/media/vicam.c')
-rw-r--r--drivers/usb/media/vicam.c1409
1 files changed, 1409 insertions, 0 deletions
diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
new file mode 100644
index 000000000000..4a5857c53f11
--- /dev/null
+++ b/drivers/usb/media/vicam.c
@@ -0,0 +1,1409 @@
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/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"
46
47// #define VICAM_DEBUG
48
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
55
56#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org"
57#define DRIVER_DESC "ViCam WebCam Driver"
58
59/* Define these values to match your device */
60#define USB_VICAM_VENDOR_ID 0x04c1
61#define USB_VICAM_PRODUCT_ID 0x009d
62
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
67
68#define VICAM_HEADER_SIZE 64
69
70#define clamp( x, l, h ) max_t( __typeof__( x ), \
71 ( l ), \
72 min_t( __typeof__( x ), \
73 ( h ), \
74 ( x ) ) )
75
76/* Not sure what all the bytes in these char
77 * arrays do, but they're necessary to make
78 * the camera work.
79 */
80
81static 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
87};
88
89static unsigned char setup2[] = {
90 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
91 0x00, 0x00
92};
93
94static unsigned char setup3[] = {
95 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
96};
97
98static 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,
310};
311
312static 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
352};
353
354/* rvmalloc / rvfree copied from usbvideo.c
355 *
356 * Not sure why these are not yet non-statics which I can reference through
357 * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime
358 * in the future.
359 *
360*/
361static void *rvmalloc(unsigned long size)
362{
363 void *mem;
364 unsigned long adr;
365
366 size = PAGE_ALIGN(size);
367 mem = vmalloc_32(size);
368 if (!mem)
369 return NULL;
370
371 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
372 adr = (unsigned long) mem;
373 while (size > 0) {
374 SetPageReserved(vmalloc_to_page((void *)adr));
375 adr += PAGE_SIZE;
376 size -= PAGE_SIZE;
377 }
378
379 return mem;
380}
381
382static void rvfree(void *mem, unsigned long size)
383{
384 unsigned long adr;
385
386 if (!mem)
387 return;
388
389 adr = (unsigned long) mem;
390 while ((long) size > 0) {
391 ClearPageReserved(vmalloc_to_page((void *)adr));
392 adr += PAGE_SIZE;
393 size -= PAGE_SIZE;
394 }
395 vfree(mem);
396}
397
398struct vicam_camera {
399 u16 shutter_speed; // capture shutter speed
400 u16 gain; // capture gain
401
402 u8 *raw_image; // raw data captured from the camera
403 u8 *framebuf; // processed data in RGB24 format
404 u8 *cntrlbuf; // area used to send control msgs
405
406 struct video_device vdev; // v4l video device
407 struct usb_device *udev; // usb device
408
409 /* guard against simultaneous accesses to the camera */
410 struct semaphore cam_lock;
411
412 int is_initialized;
413 u8 open_count;
414 u8 bulkEndpoint;
415 int needsDummyRead;
416
417#if defined(CONFIG_VIDEO_PROC_FS)
418 struct proc_dir_entry *proc_dir;
419#endif
420
421};
422
423static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
424static void vicam_disconnect(struct usb_interface *intf);
425static void read_frame(struct vicam_camera *cam, int framenum);
426static void vicam_decode_color(const u8 *, u8 *);
427
428static int __send_control_msg(struct vicam_camera *cam,
429 u8 request,
430 u16 value,
431 u16 index,
432 unsigned char *cp,
433 u16 size)
434{
435 int status;
436
437 /* cp must be memory that has been allocated by kmalloc */
438
439 status = usb_control_msg(cam->udev,
440 usb_sndctrlpipe(cam->udev, 0),
441 request,
442 USB_DIR_OUT | USB_TYPE_VENDOR |
443 USB_RECIP_DEVICE, value, index,
444 cp, size, 1000);
445
446 status = min(status, 0);
447
448 if (status < 0) {
449 printk(KERN_INFO "Failed sending control message, error %d.\n",
450 status);
451 }
452
453 return status;
454}
455
456static int send_control_msg(struct vicam_camera *cam,
457 u8 request,
458 u16 value,
459 u16 index,
460 unsigned char *cp,
461 u16 size)
462{
463 int status = -ENODEV;
464 down(&cam->cam_lock);
465 if (cam->udev) {
466 status = __send_control_msg(cam, request, value,
467 index, cp, size);
468 }
469 up(&cam->cam_lock);
470 return status;
471}
472static int
473initialize_camera(struct vicam_camera *cam)
474{
475 const struct {
476 u8 *data;
477 u32 size;
478 } firmware[] = {
479 { .data = setup1, .size = sizeof(setup1) },
480 { .data = setup2, .size = sizeof(setup2) },
481 { .data = setup3, .size = sizeof(setup3) },
482 { .data = setup4, .size = sizeof(setup4) },
483 { .data = setup5, .size = sizeof(setup5) },
484 { .data = setup3, .size = sizeof(setup3) },
485 { .data = NULL, .size = 0 }
486 };
487
488 int err, i;
489
490 for (i = 0, err = 0; firmware[i].data && !err; i++) {
491 memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
492
493 err = send_control_msg(cam, 0xff, 0, 0,
494 cam->cntrlbuf, firmware[i].size);
495 }
496
497 return err;
498}
499
500static int
501set_camera_power(struct vicam_camera *cam, int state)
502{
503 int status;
504
505 if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
506 return status;
507
508 if (state) {
509 send_control_msg(cam, 0x55, 1, 0, NULL, 0);
510 }
511
512 return 0;
513}
514
515static int
516vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
517{
518 void __user *user_arg = (void __user *)arg;
519 struct vicam_camera *cam = file->private_data;
520 int retval = 0;
521
522 if (!cam)
523 return -ENODEV;
524
525 switch (ioctlnr) {
526 /* query capabilities */
527 case VIDIOCGCAP:
528 {
529 struct video_capability b;
530
531 DBG("VIDIOCGCAP\n");
532 memset(&b, 0, sizeof(b));
533 strcpy(b.name, "ViCam-based Camera");
534 b.type = VID_TYPE_CAPTURE;
535 b.channels = 1;
536 b.audios = 0;
537 b.maxwidth = 320; /* VIDEOSIZE_CIF */
538 b.maxheight = 240;
539 b.minwidth = 320; /* VIDEOSIZE_48_48 */
540 b.minheight = 240;
541
542 if (copy_to_user(user_arg, &b, sizeof(b)))
543 retval = -EFAULT;
544
545 break;
546 }
547 /* get/set video source - we are a camera and nothing else */
548 case VIDIOCGCHAN:
549 {
550 struct video_channel v;
551
552 DBG("VIDIOCGCHAN\n");
553 if (copy_from_user(&v, user_arg, sizeof(v))) {
554 retval = -EFAULT;
555 break;
556 }
557 if (v.channel != 0) {
558 retval = -EINVAL;
559 break;
560 }
561
562 v.channel = 0;
563 strcpy(v.name, "Camera");
564 v.tuners = 0;
565 v.flags = 0;
566 v.type = VIDEO_TYPE_CAMERA;
567 v.norm = 0;
568
569 if (copy_to_user(user_arg, &v, sizeof(v)))
570 retval = -EFAULT;
571 break;
572 }
573
574 case VIDIOCSCHAN:
575 {
576 int v;
577
578 if (copy_from_user(&v, user_arg, sizeof(v)))
579 retval = -EFAULT;
580 DBG("VIDIOCSCHAN %d\n", v);
581
582 if (retval == 0 && v != 0)
583 retval = -EINVAL;
584
585 break;
586 }
587
588 /* image properties */
589 case VIDIOCGPICT:
590 {
591 struct video_picture vp;
592 DBG("VIDIOCGPICT\n");
593 memset(&vp, 0, sizeof (struct video_picture));
594 vp.brightness = cam->gain << 8;
595 vp.depth = 24;
596 vp.palette = VIDEO_PALETTE_RGB24;
597 if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
598 retval = -EFAULT;
599 break;
600 }
601
602 case VIDIOCSPICT:
603 {
604 struct video_picture vp;
605
606 if (copy_from_user(&vp, user_arg, sizeof(vp))) {
607 retval = -EFAULT;
608 break;
609 }
610
611 DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
612 vp.palette);
613
614 cam->gain = vp.brightness >> 8;
615
616 if (vp.depth != 24
617 || vp.palette != VIDEO_PALETTE_RGB24)
618 retval = -EINVAL;
619
620 break;
621 }
622
623 /* get/set capture window */
624 case VIDIOCGWIN:
625 {
626 struct video_window vw;
627 vw.x = 0;
628 vw.y = 0;
629 vw.width = 320;
630 vw.height = 240;
631 vw.chromakey = 0;
632 vw.flags = 0;
633 vw.clips = NULL;
634 vw.clipcount = 0;
635
636 DBG("VIDIOCGWIN\n");
637
638 if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
639 retval = -EFAULT;
640
641 // I'm not sure what the deal with a capture window is, it is very poorly described
642 // in the doc. So I won't support it now.
643 break;
644 }
645
646 case VIDIOCSWIN:
647 {
648
649 struct video_window vw;
650
651 if (copy_from_user(&vw, user_arg, sizeof(vw))) {
652 retval = -EFAULT;
653 break;
654 }
655
656 DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
657
658 if ( vw.width != 320 || vw.height != 240 )
659 retval = -EFAULT;
660
661 break;
662 }
663
664 /* mmap interface */
665 case VIDIOCGMBUF:
666 {
667 struct video_mbuf vm;
668 int i;
669
670 DBG("VIDIOCGMBUF\n");
671 memset(&vm, 0, sizeof (vm));
672 vm.size =
673 VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
674 vm.frames = VICAM_FRAMES;
675 for (i = 0; i < VICAM_FRAMES; i++)
676 vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
677
678 if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
679 retval = -EFAULT;
680
681 break;
682 }
683
684 case VIDIOCMCAPTURE:
685 {
686 struct video_mmap vm;
687 // int video_size;
688
689 if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
690 retval = -EFAULT;
691 break;
692 }
693
694 DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
695
696 if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
697 retval = -EINVAL;
698
699 // in theory right here we'd start the image capturing
700 // (fill in a bulk urb and submit it asynchronously)
701 //
702 // Instead we're going to do a total hack job for now and
703 // retrieve the frame in VIDIOCSYNC
704
705 break;
706 }
707
708 case VIDIOCSYNC:
709 {
710 int frame;
711
712 if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
713 retval = -EFAULT;
714 break;
715 }
716 DBG("VIDIOCSYNC: %d\n", frame);
717
718 read_frame(cam, frame);
719 vicam_decode_color(cam->raw_image,
720 cam->framebuf +
721 frame * VICAM_MAX_FRAME_SIZE );
722
723 break;
724 }
725
726 /* pointless to implement overlay with this camera */
727 case VIDIOCCAPTURE:
728 case VIDIOCGFBUF:
729 case VIDIOCSFBUF:
730 case VIDIOCKEY:
731 retval = -EINVAL;
732 break;
733
734 /* tuner interface - we have none */
735 case VIDIOCGTUNER:
736 case VIDIOCSTUNER:
737 case VIDIOCGFREQ:
738 case VIDIOCSFREQ:
739 retval = -EINVAL;
740 break;
741
742 /* audio interface - we have none */
743 case VIDIOCGAUDIO:
744 case VIDIOCSAUDIO:
745 retval = -EINVAL;
746 break;
747 default:
748 retval = -ENOIOCTLCMD;
749 break;
750 }
751
752 return retval;
753}
754
755static int
756vicam_open(struct inode *inode, struct file *file)
757{
758 struct video_device *dev = video_devdata(file);
759 struct vicam_camera *cam =
760 (struct vicam_camera *) dev->priv;
761 DBG("open\n");
762
763 if (!cam) {
764 printk(KERN_ERR
765 "vicam video_device improperly initialized");
766 }
767
768 /* the videodev_lock held above us protects us from
769 * simultaneous opens...for now. we probably shouldn't
770 * rely on this fact forever.
771 */
772
773 if (cam->open_count > 0) {
774 printk(KERN_INFO
775 "vicam_open called on already opened camera");
776 return -EBUSY;
777 }
778
779 cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
780 if (!cam->raw_image) {
781 return -ENOMEM;
782 }
783
784 cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
785 if (!cam->framebuf) {
786 kfree(cam->raw_image);
787 return -ENOMEM;
788 }
789
790 cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
791 if (!cam->cntrlbuf) {
792 kfree(cam->raw_image);
793 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
794 return -ENOMEM;
795 }
796
797 // First upload firmware, then turn the camera on
798
799 if (!cam->is_initialized) {
800 initialize_camera(cam);
801
802 cam->is_initialized = 1;
803 }
804
805 set_camera_power(cam, 1);
806
807 cam->needsDummyRead = 1;
808 cam->open_count++;
809
810 file->private_data = cam;
811
812 return 0;
813}
814
815static int
816vicam_close(struct inode *inode, struct file *file)
817{
818 struct vicam_camera *cam = file->private_data;
819 int open_count;
820 struct usb_device *udev;
821
822 DBG("close\n");
823
824 /* it's not the end of the world if
825 * we fail to turn the camera off.
826 */
827
828 set_camera_power(cam, 0);
829
830 kfree(cam->raw_image);
831 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
832 kfree(cam->cntrlbuf);
833
834 down(&cam->cam_lock);
835
836 cam->open_count--;
837 open_count = cam->open_count;
838 udev = cam->udev;
839
840 up(&cam->cam_lock);
841
842 if (!open_count && !udev) {
843 kfree(cam);
844 }
845
846 return 0;
847}
848
849static void vicam_decode_color(const u8 *data, u8 *rgb)
850{
851 /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
852 * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
853 */
854
855 int i, prevY, nextY;
856
857 prevY = 512;
858 nextY = 512;
859
860 data += VICAM_HEADER_SIZE;
861
862 for( i = 0; i < 240; i++, data += 512 ) {
863 const int y = ( i * 242 ) / 240;
864
865 int j, prevX, nextX;
866 int Y, Cr, Cb;
867
868 if ( y == 242 - 1 ) {
869 nextY = -512;
870 }
871
872 prevX = 1;
873 nextX = 1;
874
875 for ( j = 0; j < 320; j++, rgb += 3 ) {
876 const int x = ( j * 512 ) / 320;
877 const u8 * const src = &data[x];
878
879 if ( x == 512 - 1 ) {
880 nextX = -1;
881 }
882
883 Cr = ( src[prevX] - src[0] ) +
884 ( src[nextX] - src[0] );
885 Cr /= 2;
886
887 Cb = ( src[prevY] - src[prevX + prevY] ) +
888 ( src[prevY] - src[nextX + prevY] ) +
889 ( src[nextY] - src[prevX + nextY] ) +
890 ( src[nextY] - src[nextX + nextY] );
891 Cb /= 4;
892
893 Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
894
895 if ( i & 1 ) {
896 int Ct = Cr;
897 Cr = Cb;
898 Cb = Ct;
899 }
900
901 if ( ( x ^ i ) & 1 ) {
902 Cr = -Cr;
903 Cb = -Cb;
904 }
905
906 rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
907 500 ) / 900, 0, 255 );
908 rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
909 ( 813 * Cr ) ) +
910 500 ) / 1000, 0, 255 );
911 rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
912 500 ) / 1300, 0, 255 );
913
914 prevX = -1;
915 }
916
917 prevY = -512;
918 }
919}
920
921static void
922read_frame(struct vicam_camera *cam, int framenum)
923{
924 unsigned char *request = cam->cntrlbuf;
925 int realShutter;
926 int n;
927 int actual_length;
928
929 if (cam->needsDummyRead) {
930 cam->needsDummyRead = 0;
931 read_frame(cam, framenum);
932 }
933
934 memset(request, 0, 16);
935 request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
936
937 request[1] = 0; // 512x242 capture
938
939 request[2] = 0x90; // the function of these two bytes
940 request[3] = 0x07; // is not yet understood
941
942 if (cam->shutter_speed > 60) {
943 // Short exposure
944 realShutter =
945 ((-15631900 / cam->shutter_speed) + 260533) / 1000;
946 request[4] = realShutter & 0xFF;
947 request[5] = (realShutter >> 8) & 0xFF;
948 request[6] = 0x03;
949 request[7] = 0x01;
950 } else {
951 // Long exposure
952 realShutter = 15600 / cam->shutter_speed - 1;
953 request[4] = 0;
954 request[5] = 0;
955 request[6] = realShutter & 0xFF;
956 request[7] = realShutter >> 8;
957 }
958
959 // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
960 request[8] = 0;
961 // bytes 9-15 do not seem to affect exposure or image quality
962
963 down(&cam->cam_lock);
964
965 if (!cam->udev) {
966 goto done;
967 }
968
969 n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
970
971 if (n < 0) {
972 printk(KERN_ERR
973 " Problem sending frame capture control message");
974 goto done;
975 }
976
977 n = usb_bulk_msg(cam->udev,
978 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
979 cam->raw_image,
980 512 * 242 + 128, &actual_length, 10000);
981
982 if (n < 0) {
983 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
984 n);
985 }
986
987 done:
988 up(&cam->cam_lock);
989}
990
991static ssize_t
992vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
993{
994 struct vicam_camera *cam = file->private_data;
995
996 DBG("read %d bytes.\n", (int) count);
997
998 if (*ppos >= VICAM_MAX_FRAME_SIZE) {
999 *ppos = 0;
1000 return 0;
1001 }
1002
1003 if (*ppos == 0) {
1004 read_frame(cam, 0);
1005 vicam_decode_color(cam->raw_image,
1006 cam->framebuf +
1007 0 * VICAM_MAX_FRAME_SIZE);
1008 }
1009
1010 count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
1011
1012 if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
1013 count = -EFAULT;
1014 } else {
1015 *ppos += count;
1016 }
1017
1018 if (count == VICAM_MAX_FRAME_SIZE) {
1019 *ppos = 0;
1020 }
1021
1022 return count;
1023}
1024
1025
1026static int
1027vicam_mmap(struct file *file, struct vm_area_struct *vma)
1028{
1029 // TODO: allocate the raw frame buffer if necessary
1030 unsigned long page, pos;
1031 unsigned long start = vma->vm_start;
1032 unsigned long size = vma->vm_end-vma->vm_start;
1033 struct vicam_camera *cam = file->private_data;
1034
1035 if (!cam)
1036 return -ENODEV;
1037
1038 DBG("vicam_mmap: %ld\n", size);
1039
1040 /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1041 * to the size the application requested for mmap and it was screwing apps up.
1042 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1043 return -EINVAL;
1044 */
1045
1046 pos = (unsigned long)cam->framebuf;
1047 while (size > 0) {
1048 page = vmalloc_to_pfn((void *)pos);
1049 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1050 return -EAGAIN;
1051
1052 start += PAGE_SIZE;
1053 pos += PAGE_SIZE;
1054 if (size > PAGE_SIZE)
1055 size -= PAGE_SIZE;
1056 else
1057 size = 0;
1058 }
1059
1060 return 0;
1061}
1062
1063#if defined(CONFIG_VIDEO_PROC_FS)
1064
1065static struct proc_dir_entry *vicam_proc_root = NULL;
1066
1067static int vicam_read_helper(char *page, char **start, off_t off,
1068 int count, int *eof, int value)
1069{
1070 char *out = page;
1071 int len;
1072
1073 out += sprintf(out, "%d",value);
1074
1075 len = out - page;
1076 len -= off;
1077 if (len < count) {
1078 *eof = 1;
1079 if (len <= 0)
1080 return 0;
1081 } else
1082 len = count;
1083
1084 *start = page + off;
1085 return len;
1086}
1087
1088static int vicam_read_proc_shutter(char *page, char **start, off_t off,
1089 int count, int *eof, void *data)
1090{
1091 return vicam_read_helper(page,start,off,count,eof,
1092 ((struct vicam_camera *)data)->shutter_speed);
1093}
1094
1095static int vicam_read_proc_gain(char *page, char **start, off_t off,
1096 int count, int *eof, void *data)
1097{
1098 return vicam_read_helper(page,start,off,count,eof,
1099 ((struct vicam_camera *)data)->gain);
1100}
1101
1102static int
1103vicam_write_proc_shutter(struct file *file, const char *buffer,
1104 unsigned long count, void *data)
1105{
1106 u16 stmp;
1107 char kbuf[8];
1108 struct vicam_camera *cam = (struct vicam_camera *) data;
1109
1110 if (count > 6)
1111 return -EINVAL;
1112
1113 if (copy_from_user(kbuf, buffer, count))
1114 return -EFAULT;
1115
1116 stmp = (u16) simple_strtoul(kbuf, NULL, 10);
1117 if (stmp < 4 || stmp > 32000)
1118 return -EINVAL;
1119
1120 cam->shutter_speed = stmp;
1121
1122 return count;
1123}
1124
1125static int
1126vicam_write_proc_gain(struct file *file, const char *buffer,
1127 unsigned long count, void *data)
1128{
1129 u16 gtmp;
1130 char kbuf[8];
1131
1132 struct vicam_camera *cam = (struct vicam_camera *) data;
1133
1134 if (count > 4)
1135 return -EINVAL;
1136
1137 if (copy_from_user(kbuf, buffer, count))
1138 return -EFAULT;
1139
1140 gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
1141 if (gtmp > 255)
1142 return -EINVAL;
1143 cam->gain = gtmp;
1144
1145 return count;
1146}
1147
1148static void
1149vicam_create_proc_root(void)
1150{
1151 vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0);
1152
1153 if (vicam_proc_root)
1154 vicam_proc_root->owner = THIS_MODULE;
1155 else
1156 printk(KERN_ERR
1157 "could not create /proc entry for vicam!");
1158}
1159
1160static void
1161vicam_destroy_proc_root(void)
1162{
1163 if (vicam_proc_root)
1164 remove_proc_entry("video/vicam", 0);
1165}
1166
1167static void
1168vicam_create_proc_entry(struct vicam_camera *cam)
1169{
1170 char name[64];
1171 struct proc_dir_entry *ent;
1172
1173 DBG(KERN_INFO "vicam: creating proc entry\n");
1174
1175 if (!vicam_proc_root || !cam) {
1176 printk(KERN_INFO
1177 "vicam: could not create proc entry, %s pointer is null.\n",
1178 (!cam ? "camera" : "root"));
1179 return;
1180 }
1181
1182 sprintf(name, "video%d", cam->vdev.minor);
1183
1184 cam->proc_dir = create_proc_entry(name, S_IFDIR, vicam_proc_root);
1185
1186 if ( !cam->proc_dir )
1187 return; // FIXME: We should probably return an error here
1188
1189 ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
1190 cam->proc_dir);
1191 if (ent) {
1192 ent->data = cam;
1193 ent->read_proc = vicam_read_proc_shutter;
1194 ent->write_proc = vicam_write_proc_shutter;
1195 ent->size = 64;
1196 }
1197
1198 ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
1199 cam->proc_dir);
1200 if (ent) {
1201 ent->data = cam;
1202 ent->read_proc = vicam_read_proc_gain;
1203 ent->write_proc = vicam_write_proc_gain;
1204 ent->size = 64;
1205 }
1206}
1207
1208static void
1209vicam_destroy_proc_entry(void *ptr)
1210{
1211 struct vicam_camera *cam = (struct vicam_camera *) ptr;
1212 char name[16];
1213
1214 if ( !cam->proc_dir )
1215 return;
1216
1217 sprintf(name, "video%d", cam->vdev.minor);
1218 remove_proc_entry("shutter", cam->proc_dir);
1219 remove_proc_entry("gain", cam->proc_dir);
1220 remove_proc_entry(name,vicam_proc_root);
1221 cam->proc_dir = NULL;
1222
1223}
1224
1225#else
1226static inline void vicam_create_proc_root(void) { }
1227static inline void vicam_destroy_proc_root(void) { }
1228static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
1229static inline void vicam_destroy_proc_entry(void *ptr) { }
1230#endif
1231
1232static struct file_operations vicam_fops = {
1233 .owner = THIS_MODULE,
1234 .open = vicam_open,
1235 .release = vicam_close,
1236 .read = vicam_read,
1237 .mmap = vicam_mmap,
1238 .ioctl = vicam_ioctl,
1239 .llseek = no_llseek,
1240};
1241
1242static struct video_device vicam_template = {
1243 .owner = THIS_MODULE,
1244 .name = "ViCam-based USB Camera",
1245 .type = VID_TYPE_CAPTURE,
1246 .hardware = VID_HARDWARE_VICAM,
1247 .fops = &vicam_fops,
1248 .minor = -1,
1249};
1250
1251/* table of devices that work with this driver */
1252static struct usb_device_id vicam_table[] = {
1253 {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1254 {} /* Terminating entry */
1255};
1256
1257MODULE_DEVICE_TABLE(usb, vicam_table);
1258
1259static struct usb_driver vicam_driver = {
1260 .owner = THIS_MODULE,
1261 .name = "vicam",
1262 .probe = vicam_probe,
1263 .disconnect = vicam_disconnect,
1264 .id_table = vicam_table
1265};
1266
1267/**
1268 * vicam_probe
1269 * @intf: the interface
1270 * @id: the device id
1271 *
1272 * Called by the usb core when a new device is connected that it thinks
1273 * this driver might be interested in.
1274 */
1275static int
1276vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
1277{
1278 struct usb_device *dev = interface_to_usbdev(intf);
1279 int bulkEndpoint = 0;
1280 const struct usb_host_interface *interface;
1281 const struct usb_endpoint_descriptor *endpoint;
1282 struct vicam_camera *cam;
1283
1284 printk(KERN_INFO "ViCam based webcam connected\n");
1285
1286 interface = intf->cur_altsetting;
1287
1288 DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1289 interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
1290 endpoint = &interface->endpoint[0].desc;
1291
1292 if ((endpoint->bEndpointAddress & 0x80) &&
1293 ((endpoint->bmAttributes & 3) == 0x02)) {
1294 /* we found a bulk in endpoint */
1295 bulkEndpoint = endpoint->bEndpointAddress;
1296 } else {
1297 printk(KERN_ERR
1298 "No bulk in endpoint was found ?! (this is bad)\n");
1299 }
1300
1301 if ((cam =
1302 kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1303 printk(KERN_WARNING
1304 "could not allocate kernel memory for vicam_camera struct\n");
1305 return -ENOMEM;
1306 }
1307
1308 memset(cam, 0, sizeof (struct vicam_camera));
1309
1310 cam->shutter_speed = 15;
1311
1312 init_MUTEX(&cam->cam_lock);
1313
1314 memcpy(&cam->vdev, &vicam_template,
1315 sizeof (vicam_template));
1316 cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only
1317
1318 cam->udev = dev;
1319 cam->bulkEndpoint = bulkEndpoint;
1320
1321 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1322 kfree(cam);
1323 printk(KERN_WARNING "video_register_device failed\n");
1324 return -EIO;
1325 }
1326
1327 vicam_create_proc_entry(cam);
1328
1329 printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1330
1331 usb_set_intfdata (intf, cam);
1332
1333 return 0;
1334}
1335
1336static void
1337vicam_disconnect(struct usb_interface *intf)
1338{
1339 int open_count;
1340 struct vicam_camera *cam = usb_get_intfdata (intf);
1341 usb_set_intfdata (intf, NULL);
1342
1343 /* we must unregister the device before taking its
1344 * cam_lock. This is because the video open call
1345 * holds the same lock as video unregister. if we
1346 * unregister inside of the cam_lock and open also
1347 * uses the cam_lock, we get deadlock.
1348 */
1349
1350 video_unregister_device(&cam->vdev);
1351
1352 /* stop the camera from being used */
1353
1354 down(&cam->cam_lock);
1355
1356 /* mark the camera as gone */
1357
1358 cam->udev = NULL;
1359
1360 vicam_destroy_proc_entry(cam);
1361
1362 /* the only thing left to do is synchronize with
1363 * our close/release function on who should release
1364 * the camera memory. if there are any users using the
1365 * camera, it's their job. if there are no users,
1366 * it's ours.
1367 */
1368
1369 open_count = cam->open_count;
1370
1371 up(&cam->cam_lock);
1372
1373 if (!open_count) {
1374 kfree(cam);
1375 }
1376
1377 printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1378}
1379
1380/*
1381 */
1382static int __init
1383usb_vicam_init(void)
1384{
1385 int retval;
1386 DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1387 vicam_create_proc_root();
1388 retval = usb_register(&vicam_driver);
1389 if (retval)
1390 printk(KERN_WARNING "usb_register failed!\n");
1391 return retval;
1392}
1393
1394static void __exit
1395usb_vicam_exit(void)
1396{
1397 DBG(KERN_INFO
1398 "ViCam-based WebCam driver shutdown\n");
1399
1400 usb_deregister(&vicam_driver);
1401 vicam_destroy_proc_root();
1402}
1403
1404module_init(usb_vicam_init);
1405module_exit(usb_vicam_exit);
1406
1407MODULE_AUTHOR(DRIVER_AUTHOR);
1408MODULE_DESCRIPTION(DRIVER_DESC);
1409MODULE_LICENSE("GPL");