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