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