blob: ff555129c82f2830d45ec0b3a7e9e30fe3d555b3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Bas Bloemsaat81409ed2006-09-03 09:47:41 -030010 * Supports Compro PS39U WebCam
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 * This source code is based heavily on the CPiA webcam driver which was
27 * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
28 *
29 * Portions of this code were also copied from usbvideo.c
30 *
Michael Opdenacker59c51592007-05-09 08:57:56 +020031 * Special thanks to the whole team at Sourceforge for help making
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 * this driver become a reality. Notably:
33 * Andy Armstrong who reverse engineered the color encoding and
34 * Pavel Machek and Chris Cheney who worked on reverse engineering the
35 * camera controls and wrote the first generation driver.
36 */
37
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/init.h>
41#include <linux/videodev.h>
42#include <linux/usb.h>
43#include <linux/vmalloc.h>
44#include <linux/slab.h>
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010045#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#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
Bas Bloemsaat81409ed2006-09-03 09:47:41 -030063#define USB_COMPRO_VENDOR_ID 0x0602
64#define USB_COMPRO_PRODUCT_ID 0x1001
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#define VICAM_BYTES_PER_PIXEL 3
67#define VICAM_MAX_READ_SIZE (512*242+128)
68#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
69#define VICAM_FRAMES 2
70
71#define VICAM_HEADER_SIZE 64
72
73#define clamp( x, l, h ) max_t( __typeof__( x ), \
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030074 ( l ), \
75 min_t( __typeof__( x ), \
76 ( h ), \
77 ( x ) ) )
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/* Not sure what all the bytes in these char
80 * arrays do, but they're necessary to make
81 * the camera work.
82 */
83
84static unsigned char setup1[] = {
85 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
86 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
87 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
88 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
89 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
90};
91
92static unsigned char setup2[] = {
93 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
94 0x00, 0x00
95};
96
97static unsigned char setup3[] = {
98 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
99};
100
101static unsigned char setup4[] = {
102 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
103 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
104 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
105 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
106 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
107 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
108 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
109 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
110 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
111 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
112 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
113 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
114 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
115 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
116 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
117 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
118 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
119 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
120 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
121 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
122 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
123 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
124 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
125 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
126 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
127 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
128 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
129 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
130 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
131 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
132 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
133 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
134 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
135 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
136 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
137 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
138 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
139 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
140 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
141 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
142 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
143 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
144 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
145 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
146 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
147 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
148 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
149 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
150 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
151 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
152 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
153 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
154 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
155 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
156 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
157 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
158 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
159 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
160 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
161 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
162 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
163 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
164 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
165 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
166 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
167 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
168 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
169 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
170 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
171 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
172 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
173 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
174 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
175 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
176 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
177 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
178 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
179 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
180 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
181 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
182 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
183 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
184 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
185 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
186 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
187 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
188 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
189 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
190 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
191 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
192 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
193 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
194 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
195 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
196 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
197 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
198 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
199 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
200 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
201 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
202 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
203 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
204 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
205 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
206 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
207 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
208 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
209 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
210 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
211 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
212 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
213 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
214 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
215 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
216 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
217 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
218 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
219 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
220 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
221 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
222 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
223 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
224 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
225 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
226 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
227 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
228 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
229 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
230 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
231 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
232 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
233 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
234 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
235 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
236 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
237 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
238 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
239 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
240 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
241 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
242 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
243 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
244 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
245 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
246 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
247 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
248 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
249 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
250 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
251 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
252 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
253 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
254 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
255 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
256 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
257 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
258 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
259 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
260 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
261 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
262 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
263 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
264 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
265 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
266 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
267 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
268 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
269 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
270 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
271 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
272 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
273 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
274 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
275 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
276 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
277 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
278 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
279 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
280 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
281 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
282 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
283 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
284 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
285 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
286 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
287 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
288 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
289 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
290 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313};
314
315static unsigned char setup5[] = {
316 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
317 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
318 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
319 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
320 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
321 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
322 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
323 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
324 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
325 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
326 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
327 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
328 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
329 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
330 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
331 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
332 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
333 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
334 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
335 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
336 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
337 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
338 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
339 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
340 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
341 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
342 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
343 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
344 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
345 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
346 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
347 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
348 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
349 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
350 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
351 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
352 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
353 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
354 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
355};
356
357/* rvmalloc / rvfree copied from usbvideo.c
358 *
359 * Not sure why these are not yet non-statics which I can reference through
360 * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime
361 * in the future.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300362 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363*/
364static void *rvmalloc(unsigned long size)
365{
366 void *mem;
367 unsigned long adr;
368
369 size = PAGE_ALIGN(size);
370 mem = vmalloc_32(size);
371 if (!mem)
372 return NULL;
373
374 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
375 adr = (unsigned long) mem;
376 while (size > 0) {
377 SetPageReserved(vmalloc_to_page((void *)adr));
378 adr += PAGE_SIZE;
379 size -= PAGE_SIZE;
380 }
381
382 return mem;
383}
384
385static void rvfree(void *mem, unsigned long size)
386{
387 unsigned long adr;
388
389 if (!mem)
390 return;
391
392 adr = (unsigned long) mem;
393 while ((long) size > 0) {
394 ClearPageReserved(vmalloc_to_page((void *)adr));
395 adr += PAGE_SIZE;
396 size -= PAGE_SIZE;
397 }
398 vfree(mem);
399}
400
401struct vicam_camera {
402 u16 shutter_speed; // capture shutter speed
403 u16 gain; // capture gain
404
405 u8 *raw_image; // raw data captured from the camera
406 u8 *framebuf; // processed data in RGB24 format
407 u8 *cntrlbuf; // area used to send control msgs
408
409 struct video_device vdev; // v4l video device
410 struct usb_device *udev; // usb device
411
412 /* guard against simultaneous accesses to the camera */
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100413 struct mutex cam_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 int is_initialized;
416 u8 open_count;
417 u8 bulkEndpoint;
418 int needsDummyRead;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419};
420
421static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
422static void vicam_disconnect(struct usb_interface *intf);
423static void read_frame(struct vicam_camera *cam, int framenum);
424static void vicam_decode_color(const u8 *, u8 *);
425
426static int __send_control_msg(struct vicam_camera *cam,
427 u8 request,
428 u16 value,
429 u16 index,
430 unsigned char *cp,
431 u16 size)
432{
433 int status;
434
435 /* cp must be memory that has been allocated by kmalloc */
436
437 status = usb_control_msg(cam->udev,
438 usb_sndctrlpipe(cam->udev, 0),
439 request,
440 USB_DIR_OUT | USB_TYPE_VENDOR |
441 USB_RECIP_DEVICE, value, index,
442 cp, size, 1000);
443
444 status = min(status, 0);
445
446 if (status < 0) {
447 printk(KERN_INFO "Failed sending control message, error %d.\n",
448 status);
449 }
450
451 return status;
452}
453
454static int send_control_msg(struct vicam_camera *cam,
455 u8 request,
456 u16 value,
457 u16 index,
458 unsigned char *cp,
459 u16 size)
460{
461 int status = -ENODEV;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100462 mutex_lock(&cam->cam_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 if (cam->udev) {
464 status = __send_control_msg(cam, request, value,
465 index, cp, size);
466 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100467 mutex_unlock(&cam->cam_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 return status;
469}
470static int
471initialize_camera(struct vicam_camera *cam)
472{
473 const struct {
474 u8 *data;
475 u32 size;
476 } firmware[] = {
477 { .data = setup1, .size = sizeof(setup1) },
478 { .data = setup2, .size = sizeof(setup2) },
479 { .data = setup3, .size = sizeof(setup3) },
480 { .data = setup4, .size = sizeof(setup4) },
481 { .data = setup5, .size = sizeof(setup5) },
482 { .data = setup3, .size = sizeof(setup3) },
483 { .data = NULL, .size = 0 }
484 };
485
486 int err, i;
487
488 for (i = 0, err = 0; firmware[i].data && !err; i++) {
489 memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
490
491 err = send_control_msg(cam, 0xff, 0, 0,
492 cam->cntrlbuf, firmware[i].size);
493 }
494
495 return err;
496}
497
498static int
499set_camera_power(struct vicam_camera *cam, int state)
500{
501 int status;
502
503 if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
504 return status;
505
506 if (state) {
507 send_control_msg(cam, 0x55, 1, 0, NULL, 0);
508 }
509
510 return 0;
511}
512
513static int
514vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
515{
516 void __user *user_arg = (void __user *)arg;
517 struct vicam_camera *cam = file->private_data;
518 int retval = 0;
519
520 if (!cam)
521 return -ENODEV;
522
523 switch (ioctlnr) {
524 /* query capabilities */
525 case VIDIOCGCAP:
526 {
527 struct video_capability b;
528
529 DBG("VIDIOCGCAP\n");
530 memset(&b, 0, sizeof(b));
531 strcpy(b.name, "ViCam-based Camera");
532 b.type = VID_TYPE_CAPTURE;
533 b.channels = 1;
534 b.audios = 0;
535 b.maxwidth = 320; /* VIDEOSIZE_CIF */
536 b.maxheight = 240;
537 b.minwidth = 320; /* VIDEOSIZE_48_48 */
538 b.minheight = 240;
539
540 if (copy_to_user(user_arg, &b, sizeof(b)))
541 retval = -EFAULT;
542
543 break;
544 }
545 /* get/set video source - we are a camera and nothing else */
546 case VIDIOCGCHAN:
547 {
548 struct video_channel v;
549
550 DBG("VIDIOCGCHAN\n");
551 if (copy_from_user(&v, user_arg, sizeof(v))) {
552 retval = -EFAULT;
553 break;
554 }
555 if (v.channel != 0) {
556 retval = -EINVAL;
557 break;
558 }
559
560 v.channel = 0;
561 strcpy(v.name, "Camera");
562 v.tuners = 0;
563 v.flags = 0;
564 v.type = VIDEO_TYPE_CAMERA;
565 v.norm = 0;
566
567 if (copy_to_user(user_arg, &v, sizeof(v)))
568 retval = -EFAULT;
569 break;
570 }
571
572 case VIDIOCSCHAN:
573 {
574 int v;
575
576 if (copy_from_user(&v, user_arg, sizeof(v)))
577 retval = -EFAULT;
578 DBG("VIDIOCSCHAN %d\n", v);
579
580 if (retval == 0 && v != 0)
581 retval = -EINVAL;
582
583 break;
584 }
585
586 /* image properties */
587 case VIDIOCGPICT:
588 {
589 struct video_picture vp;
590 DBG("VIDIOCGPICT\n");
591 memset(&vp, 0, sizeof (struct video_picture));
592 vp.brightness = cam->gain << 8;
593 vp.depth = 24;
594 vp.palette = VIDEO_PALETTE_RGB24;
595 if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
596 retval = -EFAULT;
597 break;
598 }
599
600 case VIDIOCSPICT:
601 {
602 struct video_picture vp;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 if (copy_from_user(&vp, user_arg, sizeof(vp))) {
605 retval = -EFAULT;
606 break;
607 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
610 vp.palette);
611
612 cam->gain = vp.brightness >> 8;
613
614 if (vp.depth != 24
615 || vp.palette != VIDEO_PALETTE_RGB24)
616 retval = -EINVAL;
617
618 break;
619 }
620
621 /* get/set capture window */
622 case VIDIOCGWIN:
623 {
624 struct video_window vw;
625 vw.x = 0;
626 vw.y = 0;
627 vw.width = 320;
628 vw.height = 240;
629 vw.chromakey = 0;
630 vw.flags = 0;
631 vw.clips = NULL;
632 vw.clipcount = 0;
633
634 DBG("VIDIOCGWIN\n");
635
636 if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
637 retval = -EFAULT;
638
639 // I'm not sure what the deal with a capture window is, it is very poorly described
640 // in the doc. So I won't support it now.
641 break;
642 }
643
644 case VIDIOCSWIN:
645 {
646
647 struct video_window vw;
648
649 if (copy_from_user(&vw, user_arg, sizeof(vw))) {
650 retval = -EFAULT;
651 break;
652 }
653
654 DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 if ( vw.width != 320 || vw.height != 240 )
657 retval = -EFAULT;
658
659 break;
660 }
661
662 /* mmap interface */
663 case VIDIOCGMBUF:
664 {
665 struct video_mbuf vm;
666 int i;
667
668 DBG("VIDIOCGMBUF\n");
669 memset(&vm, 0, sizeof (vm));
670 vm.size =
671 VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
672 vm.frames = VICAM_FRAMES;
673 for (i = 0; i < VICAM_FRAMES; i++)
674 vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
675
676 if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
677 retval = -EFAULT;
678
679 break;
680 }
681
682 case VIDIOCMCAPTURE:
683 {
684 struct video_mmap vm;
685 // int video_size;
686
687 if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
688 retval = -EFAULT;
689 break;
690 }
691
692 DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
693
694 if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
695 retval = -EINVAL;
696
697 // in theory right here we'd start the image capturing
698 // (fill in a bulk urb and submit it asynchronously)
699 //
700 // Instead we're going to do a total hack job for now and
701 // retrieve the frame in VIDIOCSYNC
702
703 break;
704 }
705
706 case VIDIOCSYNC:
707 {
708 int frame;
709
710 if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
711 retval = -EFAULT;
712 break;
713 }
714 DBG("VIDIOCSYNC: %d\n", frame);
715
716 read_frame(cam, frame);
717 vicam_decode_color(cam->raw_image,
718 cam->framebuf +
719 frame * VICAM_MAX_FRAME_SIZE );
720
721 break;
722 }
723
724 /* pointless to implement overlay with this camera */
725 case VIDIOCCAPTURE:
726 case VIDIOCGFBUF:
727 case VIDIOCSFBUF:
728 case VIDIOCKEY:
729 retval = -EINVAL;
730 break;
731
732 /* tuner interface - we have none */
733 case VIDIOCGTUNER:
734 case VIDIOCSTUNER:
735 case VIDIOCGFREQ:
736 case VIDIOCSFREQ:
737 retval = -EINVAL;
738 break;
739
740 /* audio interface - we have none */
741 case VIDIOCGAUDIO:
742 case VIDIOCSAUDIO:
743 retval = -EINVAL;
744 break;
745 default:
746 retval = -ENOIOCTLCMD;
747 break;
748 }
749
750 return retval;
751}
752
753static int
754vicam_open(struct inode *inode, struct file *file)
755{
756 struct video_device *dev = video_devdata(file);
757 struct vicam_camera *cam =
758 (struct vicam_camera *) dev->priv;
759 DBG("open\n");
760
761 if (!cam) {
762 printk(KERN_ERR
763 "vicam video_device improperly initialized");
Adrian Bunkf88f8292006-03-10 23:25:06 +0100764 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 }
766
767 /* the videodev_lock held above us protects us from
768 * simultaneous opens...for now. we probably shouldn't
769 * rely on this fact forever.
770 */
771
772 if (cam->open_count > 0) {
773 printk(KERN_INFO
774 "vicam_open called on already opened camera");
775 return -EBUSY;
776 }
777
778 cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
779 if (!cam->raw_image) {
780 return -ENOMEM;
781 }
782
783 cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
784 if (!cam->framebuf) {
785 kfree(cam->raw_image);
786 return -ENOMEM;
787 }
788
789 cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
790 if (!cam->cntrlbuf) {
791 kfree(cam->raw_image);
792 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
793 return -ENOMEM;
794 }
795
796 // First upload firmware, then turn the camera on
797
798 if (!cam->is_initialized) {
799 initialize_camera(cam);
800
801 cam->is_initialized = 1;
802 }
803
804 set_camera_power(cam, 1);
805
806 cam->needsDummyRead = 1;
807 cam->open_count++;
808
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300809 file->private_data = cam;
810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 return 0;
812}
813
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300814static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815vicam_close(struct inode *inode, struct file *file)
816{
817 struct vicam_camera *cam = file->private_data;
818 int open_count;
819 struct usb_device *udev;
820
821 DBG("close\n");
822
823 /* it's not the end of the world if
824 * we fail to turn the camera off.
825 */
826
827 set_camera_power(cam, 0);
828
829 kfree(cam->raw_image);
830 rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
831 kfree(cam->cntrlbuf);
832
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100833 mutex_lock(&cam->cam_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
835 cam->open_count--;
836 open_count = cam->open_count;
837 udev = cam->udev;
838
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100839 mutex_unlock(&cam->cam_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
841 if (!open_count && !udev) {
842 kfree(cam);
843 }
844
845 return 0;
846}
847
848static void vicam_decode_color(const u8 *data, u8 *rgb)
849{
850 /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
851 * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
852 */
853
854 int i, prevY, nextY;
855
856 prevY = 512;
857 nextY = 512;
858
859 data += VICAM_HEADER_SIZE;
860
861 for( i = 0; i < 240; i++, data += 512 ) {
862 const int y = ( i * 242 ) / 240;
863
864 int j, prevX, nextX;
865 int Y, Cr, Cb;
866
867 if ( y == 242 - 1 ) {
868 nextY = -512;
869 }
870
871 prevX = 1;
872 nextX = 1;
873
874 for ( j = 0; j < 320; j++, rgb += 3 ) {
875 const int x = ( j * 512 ) / 320;
876 const u8 * const src = &data[x];
877
878 if ( x == 512 - 1 ) {
879 nextX = -1;
880 }
881
882 Cr = ( src[prevX] - src[0] ) +
883 ( src[nextX] - src[0] );
884 Cr /= 2;
885
886 Cb = ( src[prevY] - src[prevX + prevY] ) +
887 ( src[prevY] - src[nextX + prevY] ) +
888 ( src[nextY] - src[prevX + nextY] ) +
889 ( src[nextY] - src[nextX + nextY] );
890 Cb /= 4;
891
892 Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
893
894 if ( i & 1 ) {
895 int Ct = Cr;
896 Cr = Cb;
897 Cb = Ct;
898 }
899
900 if ( ( x ^ i ) & 1 ) {
901 Cr = -Cr;
902 Cb = -Cb;
903 }
904
905 rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
906 500 ) / 900, 0, 255 );
907 rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
908 ( 813 * Cr ) ) +
909 500 ) / 1000, 0, 255 );
910 rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
911 500 ) / 1300, 0, 255 );
912
913 prevX = -1;
914 }
915
916 prevY = -512;
917 }
918}
919
920static void
921read_frame(struct vicam_camera *cam, int framenum)
922{
923 unsigned char *request = cam->cntrlbuf;
924 int realShutter;
925 int n;
926 int actual_length;
927
928 if (cam->needsDummyRead) {
929 cam->needsDummyRead = 0;
930 read_frame(cam, framenum);
931 }
932
933 memset(request, 0, 16);
934 request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
935
936 request[1] = 0; // 512x242 capture
937
938 request[2] = 0x90; // the function of these two bytes
939 request[3] = 0x07; // is not yet understood
940
941 if (cam->shutter_speed > 60) {
942 // Short exposure
943 realShutter =
944 ((-15631900 / cam->shutter_speed) + 260533) / 1000;
945 request[4] = realShutter & 0xFF;
946 request[5] = (realShutter >> 8) & 0xFF;
947 request[6] = 0x03;
948 request[7] = 0x01;
949 } else {
950 // Long exposure
951 realShutter = 15600 / cam->shutter_speed - 1;
952 request[4] = 0;
953 request[5] = 0;
954 request[6] = realShutter & 0xFF;
955 request[7] = realShutter >> 8;
956 }
957
958 // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
959 request[8] = 0;
960 // bytes 9-15 do not seem to affect exposure or image quality
961
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100962 mutex_lock(&cam->cam_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
964 if (!cam->udev) {
965 goto done;
966 }
967
968 n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
969
970 if (n < 0) {
971 printk(KERN_ERR
972 " Problem sending frame capture control message");
973 goto done;
974 }
975
976 n = usb_bulk_msg(cam->udev,
977 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
978 cam->raw_image,
979 512 * 242 + 128, &actual_length, 10000);
980
981 if (n < 0) {
982 printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
983 n);
984 }
985
986 done:
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100987 mutex_unlock(&cam->cam_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988}
989
990static ssize_t
991vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
992{
993 struct vicam_camera *cam = file->private_data;
994
995 DBG("read %d bytes.\n", (int) count);
996
997 if (*ppos >= VICAM_MAX_FRAME_SIZE) {
998 *ppos = 0;
999 return 0;
1000 }
1001
1002 if (*ppos == 0) {
1003 read_frame(cam, 0);
1004 vicam_decode_color(cam->raw_image,
1005 cam->framebuf +
1006 0 * VICAM_MAX_FRAME_SIZE);
1007 }
1008
1009 count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
1010
1011 if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
1012 count = -EFAULT;
1013 } else {
1014 *ppos += count;
1015 }
1016
1017 if (count == VICAM_MAX_FRAME_SIZE) {
1018 *ppos = 0;
1019 }
1020
1021 return count;
1022}
1023
1024
1025static int
1026vicam_mmap(struct file *file, struct vm_area_struct *vma)
1027{
1028 // TODO: allocate the raw frame buffer if necessary
1029 unsigned long page, pos;
1030 unsigned long start = vma->vm_start;
1031 unsigned long size = vma->vm_end-vma->vm_start;
1032 struct vicam_camera *cam = file->private_data;
1033
1034 if (!cam)
1035 return -ENODEV;
1036
1037 DBG("vicam_mmap: %ld\n", size);
1038
1039 /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1040 * to the size the application requested for mmap and it was screwing apps up.
1041 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1042 return -EINVAL;
1043 */
1044
1045 pos = (unsigned long)cam->framebuf;
1046 while (size > 0) {
1047 page = vmalloc_to_pfn((void *)pos);
1048 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1049 return -EAGAIN;
1050
1051 start += PAGE_SIZE;
1052 pos += PAGE_SIZE;
1053 if (size > PAGE_SIZE)
1054 size -= PAGE_SIZE;
1055 else
1056 size = 0;
1057 }
1058
1059 return 0;
1060}
1061
Arjan van de Venfa027c22007-02-12 00:55:33 -08001062static const struct file_operations vicam_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 .owner = THIS_MODULE,
1064 .open = vicam_open,
1065 .release = vicam_close,
1066 .read = vicam_read,
1067 .mmap = vicam_mmap,
1068 .ioctl = vicam_ioctl,
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02001069 .compat_ioctl = v4l_compat_ioctl32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 .llseek = no_llseek,
1071};
1072
1073static struct video_device vicam_template = {
1074 .owner = THIS_MODULE,
1075 .name = "ViCam-based USB Camera",
1076 .type = VID_TYPE_CAPTURE,
1077 .hardware = VID_HARDWARE_VICAM,
1078 .fops = &vicam_fops,
1079 .minor = -1,
1080};
1081
1082/* table of devices that work with this driver */
1083static struct usb_device_id vicam_table[] = {
1084 {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
Bas Bloemsaat81409ed2006-09-03 09:47:41 -03001085 {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 {} /* Terminating entry */
1087};
1088
1089MODULE_DEVICE_TABLE(usb, vicam_table);
1090
1091static struct usb_driver vicam_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 .name = "vicam",
1093 .probe = vicam_probe,
1094 .disconnect = vicam_disconnect,
1095 .id_table = vicam_table
1096};
1097
1098/**
1099 * vicam_probe
1100 * @intf: the interface
1101 * @id: the device id
1102 *
1103 * Called by the usb core when a new device is connected that it thinks
1104 * this driver might be interested in.
1105 */
1106static int
1107vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
1108{
1109 struct usb_device *dev = interface_to_usbdev(intf);
1110 int bulkEndpoint = 0;
1111 const struct usb_host_interface *interface;
1112 const struct usb_endpoint_descriptor *endpoint;
1113 struct vicam_camera *cam;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001114
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 printk(KERN_INFO "ViCam based webcam connected\n");
1116
1117 interface = intf->cur_altsetting;
1118
1119 DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1120 interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
1121 endpoint = &interface->endpoint[0].desc;
1122
1123 if ((endpoint->bEndpointAddress & 0x80) &&
1124 ((endpoint->bmAttributes & 3) == 0x02)) {
1125 /* we found a bulk in endpoint */
1126 bulkEndpoint = endpoint->bEndpointAddress;
1127 } else {
1128 printk(KERN_ERR
1129 "No bulk in endpoint was found ?! (this is bad)\n");
1130 }
1131
1132 if ((cam =
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07001133 kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 printk(KERN_WARNING
1135 "could not allocate kernel memory for vicam_camera struct\n");
1136 return -ENOMEM;
1137 }
1138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
1140 cam->shutter_speed = 15;
1141
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001142 mutex_init(&cam->cam_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
1144 memcpy(&cam->vdev, &vicam_template,
1145 sizeof (vicam_template));
1146 cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only
1147
1148 cam->udev = dev;
1149 cam->bulkEndpoint = bulkEndpoint;
1150
1151 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1152 kfree(cam);
1153 printk(KERN_WARNING "video_register_device failed\n");
1154 return -EIO;
1155 }
1156
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1158
1159 usb_set_intfdata (intf, cam);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 return 0;
1162}
1163
1164static void
1165vicam_disconnect(struct usb_interface *intf)
1166{
1167 int open_count;
1168 struct vicam_camera *cam = usb_get_intfdata (intf);
1169 usb_set_intfdata (intf, NULL);
1170
1171 /* we must unregister the device before taking its
1172 * cam_lock. This is because the video open call
1173 * holds the same lock as video unregister. if we
1174 * unregister inside of the cam_lock and open also
1175 * uses the cam_lock, we get deadlock.
1176 */
1177
1178 video_unregister_device(&cam->vdev);
1179
1180 /* stop the camera from being used */
1181
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001182 mutex_lock(&cam->cam_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
1184 /* mark the camera as gone */
1185
1186 cam->udev = NULL;
1187
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 /* the only thing left to do is synchronize with
1189 * our close/release function on who should release
1190 * the camera memory. if there are any users using the
1191 * camera, it's their job. if there are no users,
1192 * it's ours.
1193 */
1194
1195 open_count = cam->open_count;
1196
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001197 mutex_unlock(&cam->cam_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
1199 if (!open_count) {
1200 kfree(cam);
1201 }
1202
1203 printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1204}
1205
1206/*
1207 */
1208static int __init
1209usb_vicam_init(void)
1210{
1211 int retval;
1212 DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 retval = usb_register(&vicam_driver);
1214 if (retval)
1215 printk(KERN_WARNING "usb_register failed!\n");
1216 return retval;
1217}
1218
1219static void __exit
1220usb_vicam_exit(void)
1221{
1222 DBG(KERN_INFO
1223 "ViCam-based WebCam driver shutdown\n");
1224
1225 usb_deregister(&vicam_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226}
1227
1228module_init(usb_vicam_init);
1229module_exit(usb_vicam_exit);
1230
1231MODULE_AUTHOR(DRIVER_AUTHOR);
1232MODULE_DESCRIPTION(DRIVER_DESC);
1233MODULE_LICENSE("GPL");