blob: 5d23131988076ab9f2ebcd63750f42dcb0ce285e [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * sonix sn9c102 (bayer) library
3 * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
4 * Add Pas106 Stefano Mozzi (C) 2004
5 *
6 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#define MODULE_NAME "sonixb"
24
25#include "gspca.h"
26
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -030027#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
28static const char version[] = "2.1.7";
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030029
30MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
31MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
32MODULE_LICENSE("GPL");
33
34/* specific webcam descriptor */
35struct sd {
36 struct gspca_dev gspca_dev; /* !! must be the first item */
37
Hans de Goededcef3232008-07-10 10:40:53 -030038 struct sd_desc sd_desc; /* our nctrls differ dependend upon the
39 sensor, so we use a per cam copy */
40 atomic_t avg_lum;
41
42 unsigned short gain;
43 unsigned short exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030044 unsigned char brightness;
Hans de Goededcef3232008-07-10 10:40:53 -030045 unsigned char autogain;
46 unsigned char autogain_ignore_frames;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030047
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -030048 unsigned char fr_h_sz; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030049 char sensor; /* Type of image sensor chip */
Hans de Goededcef3232008-07-10 10:40:53 -030050 char sensor_has_gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030051#define SENSOR_HV7131R 0
52#define SENSOR_OV6650 1
53#define SENSOR_OV7630 2
54#define SENSOR_OV7630_3 3
55#define SENSOR_PAS106 4
56#define SENSOR_PAS202 5
57#define SENSOR_TAS5110 6
58#define SENSOR_TAS5130CXX 7
59};
60
61#define COMP2 0x8f
62#define COMP 0xc7 /* 0x87 //0x07 */
63#define COMP1 0xc9 /* 0x89 //0x09 */
64
65#define MCK_INIT 0x63
66#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
67
68#define SYS_CLK 0x04
69
Hans de Goededcef3232008-07-10 10:40:53 -030070/* We calculate the autogain at the end of the transfer of a frame, at this
71 moment a frame with the old settings is being transmitted, and a frame is
72 being captured with the old settings. So if we adjust the autogain we must
73 ignore atleast the 2 next frames for the new settings to come into effect
74 before doing any other adjustments */
75#define AUTOGAIN_IGNORE_FRAMES 3
76#define AUTOGAIN_DEADZONE 500
77#define DESIRED_AVG_LUM 7000
78
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030079/* V4L2 controls supported by the driver */
80static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
81static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goededcef3232008-07-10 10:40:53 -030082static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
83static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
84static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
86static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030088
89static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030090 {
91 {
92 .id = V4L2_CID_BRIGHTNESS,
93 .type = V4L2_CTRL_TYPE_INTEGER,
94 .name = "Brightness",
95 .minimum = 0,
96 .maximum = 255,
97 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -030098#define BRIGHTNESS_DEF 127
99 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300100 },
101 .set = sd_setbrightness,
102 .get = sd_getbrightness,
103 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104 {
105 {
Hans de Goededcef3232008-07-10 10:40:53 -0300106 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300107 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300108 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300109 .minimum = 0,
Hans de Goededcef3232008-07-10 10:40:53 -0300110 .maximum = 511,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -0300112#define GAIN_DEF 255
113#define GAIN_KNEE 400
114 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300115 },
Hans de Goededcef3232008-07-10 10:40:53 -0300116 .set = sd_setgain,
117 .get = sd_getgain,
118 },
Hans de Goededcef3232008-07-10 10:40:53 -0300119 {
120 {
121 .id = V4L2_CID_EXPOSURE,
122 .type = V4L2_CTRL_TYPE_INTEGER,
123 .name = "Exposure",
124#define EXPOSURE_DEF 0
125#define EXPOSURE_KNEE 353 /* 10 fps */
126 .minimum = 0,
127 .maximum = 511,
128 .step = 1,
129 .default_value = EXPOSURE_DEF,
130 .flags = 0,
131 },
132 .set = sd_setexposure,
133 .get = sd_getexposure,
134 },
Hans de Goededcef3232008-07-10 10:40:53 -0300135 {
136 {
137 .id = V4L2_CID_AUTOGAIN,
138 .type = V4L2_CTRL_TYPE_BOOLEAN,
139 .name = "Automatic Gain (and Exposure)",
140 .minimum = 0,
141 .maximum = 1,
142 .step = 1,
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300143#define AUTOGAIN_DEF 1
144 .default_value = AUTOGAIN_DEF,
Hans de Goededcef3232008-07-10 10:40:53 -0300145 .flags = 0,
146 },
147 .set = sd_setautogain,
148 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300149 },
150};
151
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300152static struct v4l2_pix_format vga_mode[] = {
153 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
154 .bytesperline = 160,
155 .sizeimage = 160 * 120,
156 .colorspace = V4L2_COLORSPACE_SRGB,
157 .priv = 2},
158 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
159 .bytesperline = 320,
160 .sizeimage = 320 * 240,
161 .colorspace = V4L2_COLORSPACE_SRGB,
162 .priv = 1},
163 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
164 .bytesperline = 640,
165 .sizeimage = 640 * 480,
166 .colorspace = V4L2_COLORSPACE_SRGB,
167 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300168};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300169static struct v4l2_pix_format sif_mode[] = {
170 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
171 .bytesperline = 176,
172 .sizeimage = 176 * 144,
173 .colorspace = V4L2_COLORSPACE_SRGB,
174 .priv = 1},
175 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
176 .bytesperline = 352,
177 .sizeimage = 352 * 288,
178 .colorspace = V4L2_COLORSPACE_SRGB,
179 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300180};
181
182static const __u8 probe_ov7630[] = {0x08, 0x44};
183
184static const __u8 initHv7131[] = {
185 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
186 0x00, 0x00,
187 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
188 0x28, 0x1e, 0x60, 0x8a, 0x20,
189 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
190};
191static const __u8 hv7131_sensor_init[][8] = {
192 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
193 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
194 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
195 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
196 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
197};
198static const __u8 initOv6650[] = {
199 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
200 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
202 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
203};
204static const __u8 ov6650_sensor_init[][8] =
205{
206 /* Bright, contrast, etc are set througth SCBB interface.
207 * AVCAP on win2 do not send any data on this controls. */
208 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300209
210 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300211 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300212 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300213 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300214 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300215 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
216/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
217 * THIS SET GREEN SCREEN
218 * (pixels could be innverted in decode kind of "brg",
219 * but blue wont be there. Avoid this data ... */
220 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
221 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
222 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300223 /* Disable autobright ? */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300224 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300225 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300226 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
227 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300228 {0xa0, 0x60, 0x10, 0x57, 0x99, 0x04, 0x94, 0x16},
Hans de Goededcef3232008-07-10 10:40:53 -0300229 /* Framerate adjust register for artificial light 50 hz flicker
230 compensation, identical to ov6630 0x2b register, see 6630 datasheet.
231 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
232 {0xa0, 0x60, 0x2b, 0x4f, 0x99, 0x04, 0x94, 0x15},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300233};
Hans de Goededcef3232008-07-10 10:40:53 -0300234
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300235static const __u8 initOv7630[] = {
236 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
237 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
238 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
239 0x28, 0x1e, /* H & V sizes r15 .. r16 */
240 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
241 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
242};
243static const __u8 initOv7630_3[] = {
244 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
245 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300246 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
247 0x16, 0x12, /* H & V sizes r15 .. r16 */
248 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
249 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
250 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
251 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300252};
253static const __u8 ov7630_sensor_init_com[][8] = {
254 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
255 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
256/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
257 {0xd0, 0x21, 0x12, 0x78, 0x00, 0x80, 0x34, 0x10}, /* jfm */
258 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
259 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
260 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
261 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
262 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
263 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
264 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
265/* {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10}, jfm */
266 {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, /* jfm */
267 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
268 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
269 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
270 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
271 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
272 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
273};
274static const __u8 ov7630_sensor_init[][8] = {
275 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
276 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
277 {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
278 {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
279 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
280};
281static const __u8 ov7630_sensor_init_3[][8] = {
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300282 {0xa0, 0x21, 0x10, 0x83, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
283 {0xa0, 0x21, 0x76, 0x00, 0xbd, 0x06, 0xf6, 0x16},
284 {0xa0, 0x21, 0x11, 0x00, 0xbd, 0x06, 0xf6, 0x16},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300285 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
286/* {0xb0, 0x21, 0x2a, 0xc0, 0x3c, 0x06, 0xf6, 0x1d},
287 * a0 1c,a0 1f,c0 3c frame rate ?line interval from ov6630 */
288/* {0xb0, 0x21, 0x2a, 0xa0, 0x1f, 0x06, 0xf6, 0x1d}, * from win */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300289 {0xb0, 0x21, 0x2a, 0x80, 0x60, 0x06, 0xf6, 0x1d},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300290};
291
292static const __u8 initPas106[] = {
293 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
294 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
296 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
297 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
298};
299/* compression 0x86 mckinit1 0x2b */
300static const __u8 pas106_data[][2] = {
301 {0x02, 0x04}, /* Pixel Clock Divider 6 */
302 {0x03, 0x13}, /* Frame Time MSB */
303/* {0x03, 0x12}, * Frame Time MSB */
304 {0x04, 0x06}, /* Frame Time LSB */
305/* {0x04, 0x05}, * Frame Time LSB */
306 {0x05, 0x65}, /* Shutter Time Line Offset */
307/* {0x05, 0x6d}, * Shutter Time Line Offset */
308/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
309 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
310 {0x07, 0xc1}, /* Black Level Subtract Sign */
311/* {0x07, 0x00}, * Black Level Subtract Sign */
312 {0x08, 0x06}, /* Black Level Subtract Level */
313 {0x08, 0x06}, /* Black Level Subtract Level */
314/* {0x08, 0x01}, * Black Level Subtract Level */
315 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
316 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
317 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
318 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
319 {0x0d, 0x00}, /* Color GainH Pixel */
320 {0x0e, 0x0e}, /* Global Gain */
321 {0x0f, 0x00}, /* Contrast */
322 {0x10, 0x06}, /* H&V synchro polarity */
323 {0x11, 0x06}, /* ?default */
324 {0x12, 0x06}, /* DAC scale */
325 {0x14, 0x02}, /* ?default */
326 {0x13, 0x01}, /* Validate Settings */
327};
328static const __u8 initPas202[] = {
329 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
330 0x00, 0x00,
331 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
332 0x28, 0x1e, 0x28, 0x89, 0x30,
333 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
334};
335static const __u8 pas202_sensor_init[][8] = {
336 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
337 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
338 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
339 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
340 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
341 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
342 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
343 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
344 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
345 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
346 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
347 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
348
349 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
350 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
351 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
352 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
353 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
354 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
355 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
356 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
357};
358
359static const __u8 initTas5110[] = {
360 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
361 0x00, 0x00,
362 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
363 0x16, 0x12, 0x60, 0x86, 0x2b,
364 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
365};
366static const __u8 tas5110_sensor_init[][8] = {
367 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
368 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
369 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
370};
371
372static const __u8 initTas5130[] = {
373 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
374 0x00, 0x00,
375 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
376 0x28, 0x1e, 0x60, COMP, MCK_INIT,
377 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
378};
379static const __u8 tas5130_sensor_init[][8] = {
380/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
381 * shutter 0x47 short exposure? */
382 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
383 /* shutter 0x01 long exposure */
384 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
385};
386
387static void reg_r(struct usb_device *dev,
388 __u16 value, __u8 *buffer)
389{
390 usb_control_msg(dev,
391 usb_rcvctrlpipe(dev, 0),
392 0, /* request */
393 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
394 value,
395 0, /* index */
396 buffer, 1,
397 500);
398}
399
400static void reg_w(struct usb_device *dev,
401 __u16 value,
402 const __u8 *buffer,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300403 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300404{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300405 __u8 tmpbuf[48];
Hans de Goede0d2a7222008-07-03 08:15:22 -0300406
407#ifdef CONFIG_VIDEO_ADV_DEBUG
408 if (len > sizeof tmpbuf) {
409 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
410 return;
411 }
412#endif
413 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300414 usb_control_msg(dev,
415 usb_sndctrlpipe(dev, 0),
416 0x08, /* request */
417 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
418 value,
419 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300420 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300421 500);
422}
423
424static int i2c_w(struct usb_device *dev, const __u8 *buffer)
425{
426 int retry = 60;
427 __u8 ByteReceive;
428
429 /* is i2c ready */
430 reg_w(dev, 0x08, buffer, 8);
431 while (retry--) {
432 msleep(10);
433 reg_r(dev, 0x08, &ByteReceive);
434 if (ByteReceive == 4)
435 return 0;
436 }
437 return -1;
438}
439
440static void i2c_w_vector(struct usb_device *dev,
441 const __u8 buffer[][8], int len)
442{
443 for (;;) {
444 reg_w(dev, 0x08, *buffer, 8);
445 len -= 8;
446 if (len <= 0)
447 break;
448 buffer++;
449 }
450}
451
452static void setbrightness(struct gspca_dev *gspca_dev)
453{
454 struct sd *sd = (struct sd *) gspca_dev;
455 __u8 value;
456
457 switch (sd->sensor) {
458 case SENSOR_OV6650: {
459 __u8 i2cOV6650[] =
460 {0xa0, 0x60, 0x06, 0x11, 0x99, 0x04, 0x94, 0x15};
461
462 i2cOV6650[3] = sd->brightness;
463 if (i2c_w(gspca_dev->dev, i2cOV6650) < 0)
464 goto err;
465 break;
466 }
467 case SENSOR_OV7630: {
468 __u8 i2cOV[] =
469 {0xa0, 0x21, 0x06, 0x36, 0xbd, 0x06, 0xf6, 0x16};
470
471 /* change reg 0x06 */
472 i2cOV[3] = sd->brightness;
473 if (i2c_w(gspca_dev->dev, i2cOV) < 0)
474 goto err;
475 break;
476 }
477 case SENSOR_PAS106: {
478 __u8 i2c1[] =
479 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
480
481 i2c1[3] = sd->brightness >> 3;
482 i2c1[2] = 0x0e;
483 if (i2c_w(gspca_dev->dev, i2c1) < 0)
484 goto err;
485 i2c1[3] = 0x01;
486 i2c1[2] = 0x13;
487 if (i2c_w(gspca_dev->dev, i2c1) < 0)
488 goto err;
489 break;
490 }
491 case SENSOR_PAS202: {
492 /* __u8 i2cpexpo1[] =
493 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
494 __u8 i2cpexpo[] =
495 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
496 __u8 i2cp202[] =
497 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
498 static __u8 i2cpdoit[] =
499 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
500
501 /* change reg 0x10 */
502 i2cpexpo[4] = 0xff - sd->brightness;
503/* if(i2c_w(gspca_dev->dev,i2cpexpo1) < 0)
504 goto err; */
505/* if(i2c_w(gspca_dev->dev,i2cpdoit) < 0)
506 goto err; */
507 if (i2c_w(gspca_dev->dev, i2cpexpo) < 0)
508 goto err;
509 if (i2c_w(gspca_dev->dev, i2cpdoit) < 0)
510 goto err;
511 i2cp202[3] = sd->brightness >> 3;
512 if (i2c_w(gspca_dev->dev, i2cp202) < 0)
513 goto err;
514 if (i2c_w(gspca_dev->dev, i2cpdoit) < 0)
515 goto err;
516 break;
517 }
Hans de Goededcef3232008-07-10 10:40:53 -0300518 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300519 __u8 i2c[] =
520 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
521
522 value = 0xff - sd->brightness;
523 i2c[4] = value;
524 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
525 if (i2c_w(gspca_dev->dev, i2c) < 0)
526 goto err;
527 break;
528 }
Hans de Goededcef3232008-07-10 10:40:53 -0300529 case SENSOR_TAS5110:
530 /* FIXME figure out howto control brightness on TAS5110 */
531 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532 }
533 return;
534err:
535 PDEBUG(D_ERR, "i2c error brightness");
536}
Hans de Goededcef3232008-07-10 10:40:53 -0300537
538static void setsensorgain(struct gspca_dev *gspca_dev)
539{
540 struct sd *sd = (struct sd *) gspca_dev;
541 unsigned short gain;
542
543 gain = (sd->gain + 1) >> 1;
544 if (gain > 255)
545 gain = 255;
546
547 switch (sd->sensor) {
548
549 case SENSOR_TAS5110: {
550 __u8 i2c[] =
551 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
552
553 i2c[4] = 255 - gain;
554 if (i2c_w(gspca_dev->dev, i2c) < 0)
555 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300556 break;
557 }
Hans de Goededcef3232008-07-10 10:40:53 -0300558 case SENSOR_OV6650: {
559 __u8 i2c[] = {0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
560 i2c[3] = gain;
561 if (i2c_w(gspca_dev->dev, i2c) < 0)
562 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300563 break;
564 }
Hans de Goededcef3232008-07-10 10:40:53 -0300565 }
566 return;
567err:
568 PDEBUG(D_ERR, "i2c error gain");
569}
570
571static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300572{
573 struct sd *sd = (struct sd *) gspca_dev;
574 __u8 gain;
575 __u8 rgb_value;
576
Hans de Goededcef3232008-07-10 10:40:53 -0300577 gain = sd->gain >> 5;
578
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300579 /* red and blue gain */
580 rgb_value = gain << 4 | gain;
581 reg_w(gspca_dev->dev, 0x10, &rgb_value, 1);
582 /* green gain */
583 rgb_value = gain;
584 reg_w(gspca_dev->dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300585
586 if (sd->sensor_has_gain)
587 setsensorgain(gspca_dev);
588}
589
590static void setexposure(struct gspca_dev *gspca_dev)
591{
592 struct sd *sd = (struct sd *) gspca_dev;
593 /* translate 0 - 255 to a number of fps in a 30 - 1 scale */
594 int fps = 30 - sd->exposure * 29 / 511;
595
596 switch (sd->sensor) {
597 case SENSOR_TAS5110: {
598 __u8 reg;
599
600 /* register 19's high nibble contains the sn9c10x clock divider
601 The high nibble configures the no fps according to the
602 formula: 60 / high_nibble. With a maximum of 30 fps */
603 reg = 60 / fps;
604 if (reg > 15)
605 reg = 15;
606 reg = (reg << 4) | 0x0b;
607 reg_w(gspca_dev->dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300608 break;
609 }
Hans de Goededcef3232008-07-10 10:40:53 -0300610 case SENSOR_OV6650: {
611 __u8 i2c[] = {0xa0, 0x60, 0x11, 0xc0, 0x00, 0x00, 0x00, 0x10};
612 i2c[3] = 30 / fps - 1;
613 if (i2c[3] > 15)
614 i2c[3] = 15;
615 i2c[3] |= 0xc0;
616 if (i2c_w(gspca_dev->dev, i2c) < 0)
617 PDEBUG(D_ERR, "i2c error exposure");
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300618 break;
619 }
Hans de Goededcef3232008-07-10 10:40:53 -0300620 }
621}
622
623
624static void do_autogain(struct gspca_dev *gspca_dev)
625{
626 struct sd *sd = (struct sd *) gspca_dev;
627 int avg_lum = atomic_read(&sd->avg_lum);
628
629 if (avg_lum == -1)
630 return;
631
632 if (sd->autogain_ignore_frames > 0)
633 sd->autogain_ignore_frames--;
634 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
635 sd->brightness * DESIRED_AVG_LUM / 127,
636 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE))
637 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300638}
639
640/* this function is called at probe time */
641static int sd_config(struct gspca_dev *gspca_dev,
642 const struct usb_device_id *id)
643{
644 struct sd *sd = (struct sd *) gspca_dev;
645 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300646 __u16 product;
647 int sif = 0;
648
Hans de Goededcef3232008-07-10 10:40:53 -0300649 /* nctrls depends upon the sensor, so we use a per cam copy */
650 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
651 gspca_dev->sd_desc = &sd->sd_desc;
652
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300653 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300654 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Hans de Goededcef3232008-07-10 10:40:53 -0300655
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300656 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300657/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300658/* case 0x0c45: * Sonix */
659 switch (product) {
660 case 0x6001: /* SN9C102 */
661 case 0x6005: /* SN9C101 */
662 case 0x6007: /* SN9C101 */
663 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300664 sd->sensor_has_gain = 1;
665 sd->sd_desc.nctrls = 4;
666 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300667 sif = 1;
668 break;
669 case 0x6009: /* SN9C101 */
670 case 0x600d: /* SN9C101 */
671 case 0x6029: /* SN9C101 */
672 sd->sensor = SENSOR_PAS106;
673 sif = 1;
674 break;
675 case 0x6011: /* SN9C101 - SN9C101G */
676 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300677 sd->sensor_has_gain = 1;
678 sd->sd_desc.nctrls = 4;
679 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300680 sif = 1;
681 break;
682 case 0x6019: /* SN9C101 */
683 case 0x602c: /* SN9C102 */
684 case 0x602e: /* SN9C102 */
685 sd->sensor = SENSOR_OV7630;
686 break;
687 case 0x60b0: /* SN9C103 */
688 sd->sensor = SENSOR_OV7630_3;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300689 sd->fr_h_sz = 18; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300690 break;
691 case 0x6024: /* SN9C102 */
692 case 0x6025: /* SN9C102 */
693 sd->sensor = SENSOR_TAS5130CXX;
694 break;
695 case 0x6028: /* SN9C102 */
696 sd->sensor = SENSOR_PAS202;
697 break;
698 case 0x602d: /* SN9C102 */
699 sd->sensor = SENSOR_HV7131R;
700 break;
701 case 0x60af: /* SN9C103 */
702 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300703 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300704 break;
705 }
706/* break; */
707/* } */
708
709 cam = &gspca_dev->cam;
710 cam->dev_name = (char *) id->driver_info;
711 cam->epaddr = 0x01;
712 if (!sif) {
713 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300714 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300715 } else {
716 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300717 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300718 }
Hans de Goededcef3232008-07-10 10:40:53 -0300719 sd->brightness = BRIGHTNESS_DEF;
720 sd->gain = GAIN_DEF;
721 sd->exposure = EXPOSURE_DEF;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300722 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300723 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
724 reg_w(gspca_dev->dev, 0x01, probe_ov7630, sizeof probe_ov7630);
725 return 0;
726}
727
728/* this function is called at open time */
729static int sd_open(struct gspca_dev *gspca_dev)
730{
731 __u8 ByteReceive;
732
733 reg_r(gspca_dev->dev, 0x00, &ByteReceive);
734 if (ByteReceive != 0x10)
735 return -ENODEV;
736 return 0;
737}
738
739static void pas106_i2cinit(struct usb_device *dev)
740{
741 int i;
742 const __u8 *data;
743 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
744
745 i = ARRAY_SIZE(pas106_data);
746 data = pas106_data[0];
747 while (--i >= 0) {
748 memcpy(&i2c1[2], data, 2);
749 /* copy 2 bytes from the template */
750 if (i2c_w(dev, i2c1) < 0)
751 PDEBUG(D_ERR, "i2c error pas106");
752 data += 2;
753 }
754}
755
756/* -- start the camera -- */
757static void sd_start(struct gspca_dev *gspca_dev)
758{
759 struct sd *sd = (struct sd *) gspca_dev;
760 struct usb_device *dev = gspca_dev->dev;
761 int mode, l;
762 const __u8 *sn9c10x;
763 __u8 reg01, reg17;
764 __u8 reg17_19[3];
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300765 static const __u8 reg15[2] = { 0x28, 0x1e };
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300766
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300767 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300768 switch (sd->sensor) {
769 case SENSOR_HV7131R:
770 sn9c10x = initHv7131;
771 reg17_19[0] = 0x60;
772 reg17_19[1] = (mode << 4) | 0x8a;
773 reg17_19[2] = 0x20;
774 break;
775 case SENSOR_OV6650:
776 sn9c10x = initOv6650;
777 reg17_19[0] = 0x68;
778 reg17_19[1] = (mode << 4) | 0x8b;
779 reg17_19[2] = 0x20;
780 break;
781 case SENSOR_OV7630:
782 sn9c10x = initOv7630;
783 reg17_19[0] = 0x68;
784 reg17_19[1] = (mode << 4) | COMP2;
785 reg17_19[2] = MCK_INIT1;
786 break;
787 case SENSOR_OV7630_3:
788 sn9c10x = initOv7630_3;
789 reg17_19[0] = 0x68;
790 reg17_19[1] = (mode << 4) | COMP2;
791 reg17_19[2] = MCK_INIT1;
792 break;
793 case SENSOR_PAS106:
794 sn9c10x = initPas106;
795 reg17_19[0] = 0x24; /* 0x28 */
796 reg17_19[1] = (mode << 4) | COMP1;
797 reg17_19[2] = MCK_INIT1;
798 break;
799 case SENSOR_PAS202:
800 sn9c10x = initPas202;
801 reg17_19[0] = mode ? 0x24 : 0x20;
802 reg17_19[1] = (mode << 4) | 0x89;
803 reg17_19[2] = 0x20;
804 break;
805 case SENSOR_TAS5110:
806 sn9c10x = initTas5110;
807 reg17_19[0] = 0x60;
808 reg17_19[1] = (mode << 4) | 0x86;
809 reg17_19[2] = 0x2b; /* 0xf3; */
810 break;
811 default:
812/* case SENSOR_TAS5130CXX: */
813 sn9c10x = initTas5130;
814 reg17_19[0] = 0x60;
815 reg17_19[1] = (mode << 4) | COMP;
816 reg17_19[2] = mode ? 0x23 : 0x43;
817 break;
818 }
819 switch (sd->sensor) {
820 case SENSOR_OV7630:
821 reg01 = 0x06;
822 reg17 = 0x29;
823 l = 0x10;
824 break;
825 case SENSOR_OV7630_3:
826 reg01 = 0x44;
827 reg17 = 0x68;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300828 l = sizeof initOv7630_3;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300829 break;
830 default:
831 reg01 = sn9c10x[0];
832 reg17 = sn9c10x[0x17 - 1];
833 l = 0x1f;
834 break;
835 }
836
837 /* reg 0x01 bit 2 video transfert on */
838 reg_w(dev, 0x01, &reg01, 1);
839 /* reg 0x17 SensorClk enable inv Clk 0x60 */
840 reg_w(dev, 0x17, &reg17, 1);
841/*fixme: for ov7630 102
842 reg_w(dev, 0x01, {0x06, sn9c10x[1]}, 2); */
843 /* Set the registers from the template */
844 reg_w(dev, 0x01, sn9c10x, l);
845 switch (sd->sensor) {
846 case SENSOR_HV7131R:
847 i2c_w_vector(dev, hv7131_sensor_init,
848 sizeof hv7131_sensor_init);
849 break;
850 case SENSOR_OV6650:
851 i2c_w_vector(dev, ov6650_sensor_init,
852 sizeof ov6650_sensor_init);
853 break;
854 case SENSOR_OV7630:
855 i2c_w_vector(dev, ov7630_sensor_init_com,
856 sizeof ov7630_sensor_init_com);
857 msleep(200);
858 i2c_w_vector(dev, ov7630_sensor_init,
859 sizeof ov7630_sensor_init);
860 break;
861 case SENSOR_OV7630_3:
862 i2c_w_vector(dev, ov7630_sensor_init_com,
863 sizeof ov7630_sensor_init_com);
864 msleep(200);
865 i2c_w_vector(dev, ov7630_sensor_init_3,
866 sizeof ov7630_sensor_init_3);
867 break;
868 case SENSOR_PAS106:
869 pas106_i2cinit(dev);
870 break;
871 case SENSOR_PAS202:
872 i2c_w_vector(dev, pas202_sensor_init,
873 sizeof pas202_sensor_init);
874 break;
875 case SENSOR_TAS5110:
876 i2c_w_vector(dev, tas5110_sensor_init,
877 sizeof tas5110_sensor_init);
878 break;
879 default:
880/* case SENSOR_TAS5130CXX: */
881 i2c_w_vector(dev, tas5130_sensor_init,
882 sizeof tas5130_sensor_init);
883 break;
884 }
885 /* H_size V_size 0x28, 0x1e maybe 640x480 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300886 reg_w(dev, 0x15, reg15, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300887 /* compression register */
888 reg_w(dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300889 if (sd->sensor != SENSOR_OV7630_3) {
890 /* H_start */
891 reg_w(dev, 0x12, &sn9c10x[0x12 - 1], 1);
892 /* V_START */
893 reg_w(dev, 0x13, &sn9c10x[0x13 - 1], 1);
894 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300895 /* reset 0x17 SensorClk enable inv Clk 0x60 */
896 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
897 reg_w(dev, 0x17, &reg17_19[0], 1);
898 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300899 if (sd->sensor != SENSOR_OV7630_3)
900 reg_w(dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300901 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
902 reg_w(dev, 0x1c, &sn9c10x[0x1c - 1], 4);
903 /* Enable video transfert */
904 reg_w(dev, 0x01, &sn9c10x[0], 1);
905 /* Compression */
906 reg_w(dev, 0x18, &reg17_19[1], 2);
907 msleep(20);
908
Hans de Goededcef3232008-07-10 10:40:53 -0300909 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300910 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -0300911 setexposure(gspca_dev);
912
913 sd->autogain_ignore_frames = 0;
914 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300915}
916
917static void sd_stopN(struct gspca_dev *gspca_dev)
918{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300919 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300920
921 ByteSend = 0x09; /* 0X00 */
922 reg_w(gspca_dev->dev, 0x01, &ByteSend, 1);
923}
924
925static void sd_stop0(struct gspca_dev *gspca_dev)
926{
927}
928
929static void sd_close(struct gspca_dev *gspca_dev)
930{
931}
932
933static void sd_pkt_scan(struct gspca_dev *gspca_dev,
934 struct gspca_frame *frame, /* target */
935 unsigned char *data, /* isoc packet */
936 int len) /* iso packet length */
937{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300938 int i;
Hans de Goededcef3232008-07-10 10:40:53 -0300939 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300940
941 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300942 for (i = 0; i < len - 6; i++) {
943 if (data[0 + i] == 0xff
944 && data[1 + i] == 0xff
945 && data[2 + i] == 0x00
946 && data[3 + i] == 0xc4
947 && data[4 + i] == 0xc4
948 && data[5 + i] == 0x96) { /* start of frame */
949 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
950 frame, data, 0);
Hans de Goededcef3232008-07-10 10:40:53 -0300951 if (i < (len - 10)) {
952 atomic_set(&sd->avg_lum, data[i + 8] +
953 (data[i + 9] << 8));
954 } else {
955 atomic_set(&sd->avg_lum, -1);
956#ifdef CONFIG_VIDEO_ADV_DEBUG
957 PDEBUG(D_STREAM, "packet too short to "
958 "get avg brightness");
959#endif
960 }
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300961 data += i + sd->fr_h_sz;
962 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300963 gspca_frame_add(gspca_dev, FIRST_PACKET,
964 frame, data, len);
965 return;
966 }
967 }
968 }
969 gspca_frame_add(gspca_dev, INTER_PACKET,
970 frame, data, len);
971}
972
973static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
974{
975 struct sd *sd = (struct sd *) gspca_dev;
976
977 sd->brightness = val;
978 if (gspca_dev->streaming)
979 setbrightness(gspca_dev);
980 return 0;
981}
982
983static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
984{
985 struct sd *sd = (struct sd *) gspca_dev;
986
987 *val = sd->brightness;
988 return 0;
989}
990
Hans de Goededcef3232008-07-10 10:40:53 -0300991static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300992{
993 struct sd *sd = (struct sd *) gspca_dev;
994
Hans de Goededcef3232008-07-10 10:40:53 -0300995 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300996 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -0300997 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300998 return 0;
999}
1000
Hans de Goededcef3232008-07-10 10:40:53 -03001001static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001002{
1003 struct sd *sd = (struct sd *) gspca_dev;
1004
Hans de Goededcef3232008-07-10 10:40:53 -03001005 *val = sd->gain;
1006 return 0;
1007}
1008
1009static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1010{
1011 struct sd *sd = (struct sd *) gspca_dev;
1012
1013 sd->exposure = val;
1014 if (gspca_dev->streaming)
1015 setexposure(gspca_dev);
1016 return 0;
1017}
1018
1019static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1020{
1021 struct sd *sd = (struct sd *) gspca_dev;
1022
1023 *val = sd->exposure;
1024 return 0;
1025}
1026
1027static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1028{
1029 struct sd *sd = (struct sd *) gspca_dev;
1030
1031 sd->autogain = val;
1032 /* when switching to autogain set defaults to make sure
1033 we are on a valid point of the autogain gain /
1034 exposure knee graph, and give this change time to
1035 take effect before doing autogain. */
1036 if (sd->autogain) {
1037 sd->exposure = EXPOSURE_DEF;
1038 sd->gain = GAIN_DEF;
1039 if (gspca_dev->streaming) {
1040 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1041 setexposure(gspca_dev);
1042 setgain(gspca_dev);
1043 }
1044 }
1045
1046 return 0;
1047}
1048
1049static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1050{
1051 struct sd *sd = (struct sd *) gspca_dev;
1052
1053 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001054 return 0;
1055}
1056
1057/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001058static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001059 .name = MODULE_NAME,
1060 .ctrls = sd_ctrls,
1061 .nctrls = ARRAY_SIZE(sd_ctrls),
1062 .config = sd_config,
1063 .open = sd_open,
1064 .start = sd_start,
1065 .stopN = sd_stopN,
1066 .stop0 = sd_stop0,
1067 .close = sd_close,
1068 .pkt_scan = sd_pkt_scan,
1069};
1070
1071/* -- module initialisation -- */
1072#define DVNM(name) .driver_info = (kernel_ulong_t) name
1073static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001074#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001075 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1076 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1077 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1078 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1079 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001080 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001081 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1082 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1083 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1084 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1085 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1086 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1087 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1088 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1089 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1090 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001091#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001092 {}
1093};
1094MODULE_DEVICE_TABLE(usb, device_table);
1095
1096/* -- device connect -- */
1097static int sd_probe(struct usb_interface *intf,
1098 const struct usb_device_id *id)
1099{
1100 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1101 THIS_MODULE);
1102}
1103
1104static struct usb_driver sd_driver = {
1105 .name = MODULE_NAME,
1106 .id_table = device_table,
1107 .probe = sd_probe,
1108 .disconnect = gspca_disconnect,
1109};
1110
1111/* -- module insert / remove -- */
1112static int __init sd_mod_init(void)
1113{
1114 if (usb_register(&sd_driver) < 0)
1115 return -1;
1116 PDEBUG(D_PROBE, "v%s registered", version);
1117 return 0;
1118}
1119static void __exit sd_mod_exit(void)
1120{
1121 usb_deregister(&sd_driver);
1122 PDEBUG(D_PROBE, "deregistered");
1123}
1124
1125module_init(sd_mod_init);
1126module_exit(sd_mod_exit);