]> err.no Git - linux-2.6/blob - drivers/media/video/usbvideo/vicam.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[linux-2.6] / drivers / media / video / usbvideo / vicam.c
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  * Supports Compro PS39U WebCam
11  *
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  *
31  * Special thanks to the whole team at Sourceforge for help making
32  * 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>
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, __func__, 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 #define USB_COMPRO_VENDOR_ID    0x0602
64 #define USB_COMPRO_PRODUCT_ID   0x1001
65
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 /* Not sure what all the bytes in these char
74  * arrays do, but they're necessary to make
75  * the camera work.
76  */
77
78 static 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
86 static unsigned char setup2[] = {
87         0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
88         0x00, 0x00
89 };
90
91 static unsigned char setup3[] = {
92         0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
93 };
94
95 static 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
309 static 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.
356  *
357 */
358 static 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
379 static 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
395 struct 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 */
407         struct mutex cam_lock;
408
409         int is_initialized;
410         u8 open_count;
411         u8 bulkEndpoint;
412         int needsDummyRead;
413 };
414
415 static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
416 static void vicam_disconnect(struct usb_interface *intf);
417 static void read_frame(struct vicam_camera *cam, int framenum);
418 static void vicam_decode_color(const u8 *, u8 *);
419
420 static 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
448 static 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;
456         mutex_lock(&cam->cam_lock);
457         if (cam->udev) {
458                 status = __send_control_msg(cam, request, value,
459                                             index, cp, size);
460         }
461         mutex_unlock(&cam->cam_lock);
462         return status;
463 }
464 static int
465 initialize_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
492 static int
493 set_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
507 static int
508 vicam_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;
597
598                         if (copy_from_user(&vp, user_arg, sizeof(vp))) {
599                                 retval = -EFAULT;
600                                 break;
601                         }
602
603                         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);
649
650                         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
747 static int
748 vicam_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");
758                 return -EINVAL;
759         }
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
803         file->private_data = cam;
804
805         return 0;
806 }
807
808 static int
809 vicam_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
827         mutex_lock(&cam->cam_lock);
828
829         cam->open_count--;
830         open_count = cam->open_count;
831         udev = cam->udev;
832
833         mutex_unlock(&cam->cam_lock);
834
835         if (!open_count && !udev) {
836                 kfree(cam);
837         }
838
839         return 0;
840 }
841
842 static 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
914 static void
915 read_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
952         // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
953         request[8] = 0;
954         // bytes 9-15 do not seem to affect exposure or image quality
955
956         mutex_lock(&cam->cam_lock);
957
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:
981         mutex_unlock(&cam->cam_lock);
982 }
983
984 static ssize_t
985 vicam_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
1019 static int
1020 vicam_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
1056 static const struct file_operations vicam_fops = {
1057         .owner          = THIS_MODULE,
1058         .open           = vicam_open,
1059         .release        = vicam_close,
1060         .read           = vicam_read,
1061         .mmap           = vicam_mmap,
1062         .ioctl          = vicam_ioctl,
1063 #ifdef CONFIG_COMPAT
1064         .compat_ioctl   = v4l_compat_ioctl32,
1065 #endif
1066         .llseek         = no_llseek,
1067 };
1068
1069 static struct video_device vicam_template = {
1070         .owner          = THIS_MODULE,
1071         .name           = "ViCam-based USB Camera",
1072         .type           = VID_TYPE_CAPTURE,
1073         .fops           = &vicam_fops,
1074         .minor          = -1,
1075 };
1076
1077 /* table of devices that work with this driver */
1078 static struct usb_device_id vicam_table[] = {
1079         {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1080         {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
1081         {}                      /* Terminating entry */
1082 };
1083
1084 MODULE_DEVICE_TABLE(usb, vicam_table);
1085
1086 static struct usb_driver vicam_driver = {
1087         .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  */
1101 static int
1102 vicam_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;
1109
1110         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 =
1128              kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1129                 printk(KERN_WARNING
1130                        "could not allocate kernel memory for vicam_camera struct\n");
1131                 return -ENOMEM;
1132         }
1133
1134
1135         cam->shutter_speed = 15;
1136
1137         mutex_init(&cam->cam_lock);
1138
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
1152         printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1153
1154         usb_set_intfdata (intf, cam);
1155
1156         return 0;
1157 }
1158
1159 static void
1160 vicam_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
1177         mutex_lock(&cam->cam_lock);
1178
1179         /* mark the camera as gone */
1180
1181         cam->udev = NULL;
1182
1183         /* 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
1192         mutex_unlock(&cam->cam_lock);
1193
1194         if (!open_count) {
1195                 kfree(cam);
1196         }
1197
1198         printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1199 }
1200
1201 /*
1202  */
1203 static int __init
1204 usb_vicam_init(void)
1205 {
1206         int retval;
1207         DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1208         retval = usb_register(&vicam_driver);
1209         if (retval)
1210                 printk(KERN_WARNING "usb_register failed!\n");
1211         return retval;
1212 }
1213
1214 static void __exit
1215 usb_vicam_exit(void)
1216 {
1217         DBG(KERN_INFO
1218                "ViCam-based WebCam driver shutdown\n");
1219
1220         usb_deregister(&vicam_driver);
1221 }
1222
1223 module_init(usb_vicam_init);
1224 module_exit(usb_vicam_exit);
1225
1226 MODULE_AUTHOR(DRIVER_AUTHOR);
1227 MODULE_DESCRIPTION(DRIVER_DESC);
1228 MODULE_LICENSE("GPL");