blob: f6bef896d3a526e1a84080eeff3700c00d9453b2 [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
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030027MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
28MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
29MODULE_LICENSE("GPL");
30
31/* specific webcam descriptor */
32struct sd {
33 struct gspca_dev gspca_dev; /* !! must be the first item */
34
Hans de Goededcef3232008-07-10 10:40:53 -030035 struct sd_desc sd_desc; /* our nctrls differ dependend upon the
36 sensor, so we use a per cam copy */
37 atomic_t avg_lum;
38
Hans de Goedead5ef80d2008-07-14 10:11:42 -030039 unsigned char gain;
40 unsigned char exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030041 unsigned char brightness;
Hans de Goededcef3232008-07-10 10:40:53 -030042 unsigned char autogain;
43 unsigned char autogain_ignore_frames;
Hans de Goede66f35822008-07-16 10:16:28 -030044 unsigned char freq; /* light freq filter setting */
Hans de Goede12ff9122008-07-17 10:30:56 -030045 unsigned char saturation;
46 unsigned char hue;
47 unsigned char contrast;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030048
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -030049 unsigned char fr_h_sz; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030050 char sensor; /* Type of image sensor chip */
51#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
Hans de Goedea975a522008-07-16 15:29:11 -030059 char sensor_has_gain;
60 __u8 sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030061};
62
63#define COMP2 0x8f
64#define COMP 0xc7 /* 0x87 //0x07 */
65#define COMP1 0xc9 /* 0x89 //0x09 */
66
67#define MCK_INIT 0x63
68#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
69
70#define SYS_CLK 0x04
71
Hans de Goededcef3232008-07-10 10:40:53 -030072/* We calculate the autogain at the end of the transfer of a frame, at this
73 moment a frame with the old settings is being transmitted, and a frame is
74 being captured with the old settings. So if we adjust the autogain we must
75 ignore atleast the 2 next frames for the new settings to come into effect
76 before doing any other adjustments */
77#define AUTOGAIN_IGNORE_FRAMES 3
Hans de Goedead5ef80d2008-07-14 10:11:42 -030078#define AUTOGAIN_DEADZONE 1000
Hans de Goededcef3232008-07-10 10:40:53 -030079#define DESIRED_AVG_LUM 7000
80
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030081/* V4L2 controls supported by the driver */
82static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
83static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goededcef3232008-07-10 10:40:53 -030084static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
86static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
88static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
89static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede66f35822008-07-16 10:16:28 -030090static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
91static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede12ff9122008-07-17 10:30:56 -030092static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val);
93static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);
94static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
95static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
96static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
97static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030098
99static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300100 {
101 {
102 .id = V4L2_CID_BRIGHTNESS,
103 .type = V4L2_CTRL_TYPE_INTEGER,
104 .name = "Brightness",
105 .minimum = 0,
106 .maximum = 255,
107 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -0300108#define BRIGHTNESS_DEF 127
109 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300110 },
111 .set = sd_setbrightness,
112 .get = sd_getbrightness,
113 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300114 {
115 {
Hans de Goededcef3232008-07-10 10:40:53 -0300116 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300117 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300118 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300119 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300120 .maximum = 255,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300121 .step = 1,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300122#define GAIN_DEF 127
123#define GAIN_KNEE 200
Hans de Goededcef3232008-07-10 10:40:53 -0300124 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300125 },
Hans de Goededcef3232008-07-10 10:40:53 -0300126 .set = sd_setgain,
127 .get = sd_getgain,
128 },
Hans de Goededcef3232008-07-10 10:40:53 -0300129 {
130 {
131 .id = V4L2_CID_EXPOSURE,
132 .type = V4L2_CTRL_TYPE_INTEGER,
133 .name = "Exposure",
Hans de Goedef4d52022008-07-15 09:36:42 -0300134#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
135#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
Hans de Goededcef3232008-07-10 10:40:53 -0300136 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300137 .maximum = 255,
Hans de Goededcef3232008-07-10 10:40:53 -0300138 .step = 1,
139 .default_value = EXPOSURE_DEF,
140 .flags = 0,
141 },
142 .set = sd_setexposure,
143 .get = sd_getexposure,
144 },
Hans de Goededcef3232008-07-10 10:40:53 -0300145 {
146 {
147 .id = V4L2_CID_AUTOGAIN,
148 .type = V4L2_CTRL_TYPE_BOOLEAN,
149 .name = "Automatic Gain (and Exposure)",
150 .minimum = 0,
151 .maximum = 1,
152 .step = 1,
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300153#define AUTOGAIN_DEF 1
154 .default_value = AUTOGAIN_DEF,
Hans de Goededcef3232008-07-10 10:40:53 -0300155 .flags = 0,
156 },
157 .set = sd_setautogain,
158 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300159 },
Hans de Goede66f35822008-07-16 10:16:28 -0300160 {
161 {
162 .id = V4L2_CID_POWER_LINE_FREQUENCY,
163 .type = V4L2_CTRL_TYPE_MENU,
164 .name = "Light frequency filter",
165 .minimum = 0,
166 .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
167 .step = 1,
168#define FREQ_DEF 1
169 .default_value = FREQ_DEF,
170 },
171 .set = sd_setfreq,
172 .get = sd_getfreq,
173 },
Hans de Goede12ff9122008-07-17 10:30:56 -0300174 {
175 {
176 .id = V4L2_CID_SATURATION,
177 .type = V4L2_CTRL_TYPE_INTEGER,
178 .name = "Saturation",
179 .minimum = 0,
180 .maximum = 255,
181 .step = 1,
182#define SATURATION_DEF 127
183 .default_value = SATURATION_DEF,
184 },
185 .set = sd_setsaturation,
186 .get = sd_getsaturation,
187 },
188 {
189 {
190 .id = V4L2_CID_HUE,
191 .type = V4L2_CTRL_TYPE_INTEGER,
192 .name = "Hue",
193 .minimum = 0,
194 .maximum = 255,
195 .step = 1,
196#define HUE_DEF 127
197 .default_value = HUE_DEF,
198 },
199 .set = sd_sethue,
200 .get = sd_gethue,
201 },
202 {
203 {
204 .id = V4L2_CID_CONTRAST,
205 .type = V4L2_CTRL_TYPE_INTEGER,
206 .name = "Contrast",
207 .minimum = 0,
208 .maximum = 255,
209 .step = 1,
210#define CONTRAST_DEF 127
211 .default_value = CONTRAST_DEF,
212 },
213 .set = sd_setcontrast,
214 .get = sd_getcontrast,
215 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300216};
217
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300218static struct v4l2_pix_format vga_mode[] = {
219 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
220 .bytesperline = 160,
221 .sizeimage = 160 * 120,
222 .colorspace = V4L2_COLORSPACE_SRGB,
223 .priv = 2},
224 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
225 .bytesperline = 320,
226 .sizeimage = 320 * 240,
227 .colorspace = V4L2_COLORSPACE_SRGB,
228 .priv = 1},
229 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
230 .bytesperline = 640,
231 .sizeimage = 640 * 480,
232 .colorspace = V4L2_COLORSPACE_SRGB,
233 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300234};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300235static struct v4l2_pix_format sif_mode[] = {
236 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
237 .bytesperline = 176,
238 .sizeimage = 176 * 144,
239 .colorspace = V4L2_COLORSPACE_SRGB,
240 .priv = 1},
241 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
242 .bytesperline = 352,
243 .sizeimage = 352 * 288,
244 .colorspace = V4L2_COLORSPACE_SRGB,
245 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300246};
247
248static const __u8 probe_ov7630[] = {0x08, 0x44};
249
250static const __u8 initHv7131[] = {
251 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
252 0x00, 0x00,
253 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
254 0x28, 0x1e, 0x60, 0x8a, 0x20,
255 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
256};
257static const __u8 hv7131_sensor_init[][8] = {
258 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
259 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
260 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
261 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
262 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
263};
264static const __u8 initOv6650[] = {
265 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
266 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
268 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
269};
270static const __u8 ov6650_sensor_init[][8] =
271{
272 /* Bright, contrast, etc are set througth SCBB interface.
273 * AVCAP on win2 do not send any data on this controls. */
274 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300275
276 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300277 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300278 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300279 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300280 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300281 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
282/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
283 * THIS SET GREEN SCREEN
284 * (pixels could be innverted in decode kind of "brg",
285 * but blue wont be there. Avoid this data ... */
286 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
287 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
288 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goede722103e2008-07-17 10:24:47 -0300289 /* Enable rgb brightness control */
290 {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
291 /* HDG: Note windows uses the line below, which sets both register 0x60
292 and 0x61 I believe these registers of the ov6650 are identical as
293 those of the ov7630, because if this is true the windows settings
294 add a bit additional red gain and a lot additional blue gain, which
295 matches my findings that the windows settings make blue much too
296 blue and red a little too red.
297 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
Hans de Goededcef3232008-07-10 10:40:53 -0300298 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300299 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
300 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300301};
Hans de Goededcef3232008-07-10 10:40:53 -0300302
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300303static const __u8 initOv7630[] = {
304 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
305 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
306 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
307 0x28, 0x1e, /* H & V sizes r15 .. r16 */
308 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
309 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
310};
311static const __u8 initOv7630_3[] = {
312 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
313 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300314 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300315 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300316 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
317 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
318 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
319 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300320};
321static const __u8 ov7630_sensor_init_com[][8] = {
322 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
323 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
324/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300325 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300326 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
327 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
328 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
329 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
330 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
331 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
332 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
Andoni Zubimendi794af522008-07-16 08:33:14 -0300333 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
334/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300335 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
336 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
337 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
338 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
339 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
340 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
341};
342static const __u8 ov7630_sensor_init[][8] = {
343 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
344 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
345 {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
346 {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
347 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
348};
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300349static const __u8 ov7630_sensor_init_3[][8] = {
350 {0xa0, 0x21, 0x2a, 0xa0, 0x00, 0x00, 0x00, 0x10},
351 {0xa0, 0x21, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x10},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300352};
353
354static const __u8 initPas106[] = {
355 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
356 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
358 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
359 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
360};
361/* compression 0x86 mckinit1 0x2b */
362static const __u8 pas106_data[][2] = {
363 {0x02, 0x04}, /* Pixel Clock Divider 6 */
364 {0x03, 0x13}, /* Frame Time MSB */
365/* {0x03, 0x12}, * Frame Time MSB */
366 {0x04, 0x06}, /* Frame Time LSB */
367/* {0x04, 0x05}, * Frame Time LSB */
368 {0x05, 0x65}, /* Shutter Time Line Offset */
369/* {0x05, 0x6d}, * Shutter Time Line Offset */
370/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
371 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
372 {0x07, 0xc1}, /* Black Level Subtract Sign */
373/* {0x07, 0x00}, * Black Level Subtract Sign */
374 {0x08, 0x06}, /* Black Level Subtract Level */
375 {0x08, 0x06}, /* Black Level Subtract Level */
376/* {0x08, 0x01}, * Black Level Subtract Level */
377 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
378 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
379 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
380 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
381 {0x0d, 0x00}, /* Color GainH Pixel */
382 {0x0e, 0x0e}, /* Global Gain */
383 {0x0f, 0x00}, /* Contrast */
384 {0x10, 0x06}, /* H&V synchro polarity */
385 {0x11, 0x06}, /* ?default */
386 {0x12, 0x06}, /* DAC scale */
387 {0x14, 0x02}, /* ?default */
388 {0x13, 0x01}, /* Validate Settings */
389};
390static const __u8 initPas202[] = {
391 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
392 0x00, 0x00,
393 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
394 0x28, 0x1e, 0x28, 0x89, 0x30,
395 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
396};
397static const __u8 pas202_sensor_init[][8] = {
398 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
399 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
400 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
401 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
402 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
403 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
404 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
405 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
406 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
407 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
408 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
409 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
410
411 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
412 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
413 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
414 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
415 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
416 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
417 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
418 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
419};
420
421static const __u8 initTas5110[] = {
422 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
423 0x00, 0x00,
424 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
425 0x16, 0x12, 0x60, 0x86, 0x2b,
426 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
427};
428static const __u8 tas5110_sensor_init[][8] = {
429 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
430 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
431 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
432};
433
434static const __u8 initTas5130[] = {
435 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
436 0x00, 0x00,
437 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
438 0x28, 0x1e, 0x60, COMP, MCK_INIT,
439 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
440};
441static const __u8 tas5130_sensor_init[][8] = {
442/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
443 * shutter 0x47 short exposure? */
444 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
445 /* shutter 0x01 long exposure */
446 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
447};
448
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300449/* get one byte in gspca_dev->usb_buf */
450static void reg_r(struct gspca_dev *gspca_dev,
451 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300452{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300453 usb_control_msg(gspca_dev->dev,
454 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300455 0, /* request */
456 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
457 value,
458 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300459 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300460 500);
461}
462
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300463static void reg_w(struct gspca_dev *gspca_dev,
464 __u16 value,
465 const __u8 *buffer,
466 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300467{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300468#ifdef CONFIG_VIDEO_ADV_DEBUG
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300469 if (len > sizeof gspca_dev->usb_buf) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300470 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
471 return;
472 }
473#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300474 memcpy(gspca_dev->usb_buf, buffer, len);
475 usb_control_msg(gspca_dev->dev,
476 usb_sndctrlpipe(gspca_dev->dev, 0),
477 0x08, /* request */
478 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
479 value,
480 0, /* index */
481 gspca_dev->usb_buf, len,
482 500);
483}
484
485static void reg_w_big(struct gspca_dev *gspca_dev,
486 __u16 value,
487 const __u8 *buffer,
488 int len)
489{
490 __u8 *tmpbuf;
491
492 tmpbuf = kmalloc(len, GFP_KERNEL);
Hans de Goede0d2a7222008-07-03 08:15:22 -0300493 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300494 usb_control_msg(gspca_dev->dev,
495 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300496 0x08, /* request */
497 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
498 value,
499 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300500 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300501 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300502 kfree(tmpbuf);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503}
504
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300505static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506{
507 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300508
509 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300510 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300511 while (retry--) {
512 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300513 reg_r(gspca_dev, 0x08);
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300514 if (gspca_dev->usb_buf[0] & 0x04) {
515 if (gspca_dev->usb_buf[0] & 0x08)
516 return -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517 return 0;
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300518 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300519 }
520 return -1;
521}
522
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300523static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300524 const __u8 buffer[][8], int len)
525{
526 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300527 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300528 len -= 8;
529 if (len <= 0)
530 break;
531 buffer++;
532 }
533}
534
535static void setbrightness(struct gspca_dev *gspca_dev)
536{
537 struct sd *sd = (struct sd *) gspca_dev;
538 __u8 value;
539
540 switch (sd->sensor) {
Hans de Goedea975a522008-07-16 15:29:11 -0300541 case SENSOR_OV6650:
Andoni Zubimendi794af522008-07-16 08:33:14 -0300542 case SENSOR_OV7630_3:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300543 case SENSOR_OV7630: {
544 __u8 i2cOV[] =
Hans de Goedea975a522008-07-16 15:29:11 -0300545 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300546
547 /* change reg 0x06 */
Hans de Goedea975a522008-07-16 15:29:11 -0300548 i2cOV[1] = sd->sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300549 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300550 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300551 goto err;
552 break;
553 }
554 case SENSOR_PAS106: {
555 __u8 i2c1[] =
556 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
557
558 i2c1[3] = sd->brightness >> 3;
559 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300560 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300561 goto err;
562 i2c1[3] = 0x01;
563 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300564 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300565 goto err;
566 break;
567 }
568 case SENSOR_PAS202: {
569 /* __u8 i2cpexpo1[] =
570 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
571 __u8 i2cpexpo[] =
572 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
573 __u8 i2cp202[] =
574 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
575 static __u8 i2cpdoit[] =
576 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
577
578 /* change reg 0x10 */
579 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300580/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300581 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300582/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300583 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300584 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300585 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300586 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300587 goto err;
588 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300589 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300590 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300591 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300592 goto err;
593 break;
594 }
Hans de Goededcef3232008-07-10 10:40:53 -0300595 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300596 __u8 i2c[] =
597 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
598
599 value = 0xff - sd->brightness;
600 i2c[4] = value;
601 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300602 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300603 goto err;
604 break;
605 }
Hans de Goededcef3232008-07-10 10:40:53 -0300606 case SENSOR_TAS5110:
607 /* FIXME figure out howto control brightness on TAS5110 */
608 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300609 }
610 return;
611err:
612 PDEBUG(D_ERR, "i2c error brightness");
613}
Hans de Goededcef3232008-07-10 10:40:53 -0300614
615static void setsensorgain(struct gspca_dev *gspca_dev)
616{
617 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea975a522008-07-16 15:29:11 -0300618 unsigned char gain = sd->gain;
Hans de Goededcef3232008-07-10 10:40:53 -0300619
620 switch (sd->sensor) {
621
622 case SENSOR_TAS5110: {
623 __u8 i2c[] =
624 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
625
Hans de Goedea975a522008-07-16 15:29:11 -0300626 i2c[4] = 255 - gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300627 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300628 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300629 break;
630 }
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300631
Hans de Goedea975a522008-07-16 15:29:11 -0300632 case SENSOR_OV6650:
633 gain >>= 1;
634 /* fall thru */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300635 case SENSOR_OV7630_3: {
Hans de Goedea975a522008-07-16 15:29:11 -0300636 __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Andoni Zubimendi794af522008-07-16 08:33:14 -0300637
Hans de Goedea975a522008-07-16 15:29:11 -0300638 i2c[1] = sd->sensor_addr;
639 i2c[3] = gain >> 2;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300640 if (i2c_w(gspca_dev, i2c) < 0)
641 goto err;
642 break;
643 }
Hans de Goededcef3232008-07-10 10:40:53 -0300644 }
645 return;
646err:
647 PDEBUG(D_ERR, "i2c error gain");
648}
649
650static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300651{
652 struct sd *sd = (struct sd *) gspca_dev;
653 __u8 gain;
654 __u8 rgb_value;
655
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300656 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300657
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300658 /* red and blue gain */
659 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300660 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300661 /* green gain */
662 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300663 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300664
665 if (sd->sensor_has_gain)
666 setsensorgain(gspca_dev);
667}
668
669static void setexposure(struct gspca_dev *gspca_dev)
670{
671 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300672
673 switch (sd->sensor) {
674 case SENSOR_TAS5110: {
675 __u8 reg;
676
677 /* register 19's high nibble contains the sn9c10x clock divider
678 The high nibble configures the no fps according to the
679 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300680 reg = 120 * sd->exposure / 1000;
681 if (reg < 2)
682 reg = 2;
683 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300684 reg = 15;
685 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300686 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300687 break;
688 }
Hans de Goedea975a522008-07-16 15:29:11 -0300689 case SENSOR_OV6650:
690 case SENSOR_OV7630_3: {
691 /* The ov6650 / ov7630 have 2 registers which both influence
692 exposure, register 11, whose low nibble sets the nr off fps
Hans de Goedef4d52022008-07-15 09:36:42 -0300693 according to: fps = 30 / (low_nibble + 1)
694
695 The fps configures the maximum exposure setting, but it is
696 possible to use less exposure then what the fps maximum
697 allows by setting register 10. register 10 configures the
698 actual exposure as quotient of the full exposure, with 0
699 being no exposure at all (not very usefull) and reg10_max
700 being max exposure possible at that framerate.
701
702 The code maps our 0 - 510 ms exposure ctrl to these 2
703 registers, trying to keep fps as high as possible.
704 */
Hans de Goedea975a522008-07-16 15:29:11 -0300705 __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
Hans de Goedef4d52022008-07-15 09:36:42 -0300706 int reg10, reg11;
Hans de Goede66f35822008-07-16 10:16:28 -0300707 /* ov6645 datasheet says reg10_max is 9a, but that uses
708 tline * 2 * reg10 as formula for calculating texpo, the
709 ov6650 probably uses the same formula as the 7730 which uses
710 tline * 4 * reg10, which explains why the reg10max we've
711 found experimentally for the ov6650 is exactly half that of
Hans de Goedea975a522008-07-16 15:29:11 -0300712 the ov6645. The ov7630 datasheet says the max is 0x41. */
Hans de Goede722103e2008-07-17 10:24:47 -0300713 const int reg10_max = (sd->sensor == SENSOR_OV6650)
714 ? 0x4d : 0x41;
Hans de Goedef4d52022008-07-15 09:36:42 -0300715
716 reg11 = (60 * sd->exposure + 999) / 1000;
717 if (reg11 < 1)
718 reg11 = 1;
719 else if (reg11 > 16)
720 reg11 = 16;
721
722 /* frame exposure time in ms = 1000 * reg11 / 30 ->
723 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
724 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
Hans de Goedea975a522008-07-16 15:29:11 -0300725
726 /* Don't allow this to get below 10 when using autogain, the
727 steps become very large (relatively) when below 10 causing
728 the image to oscilate from much too dark, to much too bright
729 and back again. */
730 if (sd->autogain && reg10 < 10)
731 reg10 = 10;
Hans de Goedef4d52022008-07-15 09:36:42 -0300732 else if (reg10 > reg10_max)
733 reg10 = reg10_max;
734
735 /* Write reg 10 and reg11 low nibble */
Hans de Goedea975a522008-07-16 15:29:11 -0300736 i2c[1] = sd->sensor_addr;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300737 i2c[3] = reg10;
738 i2c[4] |= reg11 - 1;
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300739 if (sd->sensor == SENSOR_OV7630_3) {
740 __u8 reg76 = reg10 & 0x03;
741 __u8 i2c_reg76[] = {0xa0, 0x21, 0x76, 0x00,
742 0x00, 0x00, 0x00, 0x10};
743 reg10 >>= 2;
744 i2c_reg76[3] = reg76;
745 if (i2c_w(gspca_dev, i2c_reg76) < 0)
746 PDEBUG(D_ERR, "i2c error exposure");
747 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300748 if (i2c_w(gspca_dev, i2c) < 0)
749 PDEBUG(D_ERR, "i2c error exposure");
750 break;
751 }
Hans de Goededcef3232008-07-10 10:40:53 -0300752 }
753}
754
Hans de Goede66f35822008-07-16 10:16:28 -0300755static void setfreq(struct gspca_dev *gspca_dev)
756{
757 struct sd *sd = (struct sd *) gspca_dev;
758
759 switch (sd->sensor) {
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300760 case SENSOR_OV6650:
761 case SENSOR_OV7630_3: {
Hans de Goede66f35822008-07-16 10:16:28 -0300762 /* Framerate adjust register for artificial light 50 hz flicker
763 compensation, identical to ov6630 0x2b register, see ov6630
764 datasheet.
765 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300766 __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goede66f35822008-07-16 10:16:28 -0300767 switch (sd->freq) {
768 default:
769/* case 0: * no filter*/
770/* case 2: * 60 hz */
771 i2c[3] = 0;
772 break;
773 case 1: /* 50 hz */
Hans de Goede722103e2008-07-17 10:24:47 -0300774 i2c[3] = (sd->sensor == SENSOR_OV6650)
775 ? 0x4f : 0x8a;
Hans de Goede66f35822008-07-16 10:16:28 -0300776 break;
777 }
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300778 i2c[1] = sd->sensor_addr;
Hans de Goede66f35822008-07-16 10:16:28 -0300779 if (i2c_w(gspca_dev, i2c) < 0)
780 PDEBUG(D_ERR, "i2c error setfreq");
781 break;
782 }
783 }
784}
785
Hans de Goede12ff9122008-07-17 10:30:56 -0300786static void setsaturation(struct gspca_dev *gspca_dev)
787{
788 struct sd *sd = (struct sd *) gspca_dev;
789
790 switch (sd->sensor) {
791/* case SENSOR_OV6650: */
792 case SENSOR_OV7630_3:
793 case SENSOR_OV7630: {
794 __u8 i2c[] = {0xa0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10};
795 i2c[1] = sd->sensor_addr;
796 i2c[3] = sd->saturation & 0xf0;
797 if (i2c_w(gspca_dev, i2c) < 0)
798 PDEBUG(D_ERR, "i2c error setsaturation");
799 else
800 PDEBUG(D_CONF, "saturation set to: %d",
801 (int)sd->saturation);
802 break;
803 }
804 }
805}
806
807static void sethue(struct gspca_dev *gspca_dev)
808{
809 struct sd *sd = (struct sd *) gspca_dev;
810
811 switch (sd->sensor) {
812/* case SENSOR_OV6650: */
813 case SENSOR_OV7630_3:
814 case SENSOR_OV7630: {
815 __u8 i2c[] = {0xa0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10};
816 i2c[1] = sd->sensor_addr;
817 i2c[3] = 0x20 | (sd->hue >> 3);
818 if (i2c_w(gspca_dev, i2c) < 0)
819 PDEBUG(D_ERR, "i2c error setsaturation");
820 else
821 PDEBUG(D_CONF, "hue set to: %d", (int)sd->hue);
822 break;
823 }
824 }
825}
826
827static void setcontrast(struct gspca_dev *gspca_dev)
828{
829 struct sd *sd = (struct sd *) gspca_dev;
830
831 switch (sd->sensor) {
832/* case SENSOR_OV6650: */
833 case SENSOR_OV7630_3:
834 case SENSOR_OV7630: {
835 __u8 i2c[] = {0xa0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10};
836 i2c[1] = sd->sensor_addr;
837 i2c[3] = 0x20 | (sd->contrast >> 3);
838 if (i2c_w(gspca_dev, i2c) < 0)
839 PDEBUG(D_ERR, "i2c error setcontrast");
840 else
841 PDEBUG(D_CONF, "contrast set to: %d",
842 (int)sd->contrast);
843 break;
844 }
845 }
846}
847
Hans de Goededcef3232008-07-10 10:40:53 -0300848
849static void do_autogain(struct gspca_dev *gspca_dev)
850{
851 struct sd *sd = (struct sd *) gspca_dev;
852 int avg_lum = atomic_read(&sd->avg_lum);
853
854 if (avg_lum == -1)
855 return;
856
857 if (sd->autogain_ignore_frames > 0)
858 sd->autogain_ignore_frames--;
859 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
860 sd->brightness * DESIRED_AVG_LUM / 127,
Hans de Goedea975a522008-07-16 15:29:11 -0300861 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
862 PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
863 (int)sd->gain, (int)sd->exposure);
Hans de Goededcef3232008-07-10 10:40:53 -0300864 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Hans de Goedea975a522008-07-16 15:29:11 -0300865 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300866}
867
868/* this function is called at probe time */
869static int sd_config(struct gspca_dev *gspca_dev,
870 const struct usb_device_id *id)
871{
872 struct sd *sd = (struct sd *) gspca_dev;
873 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300874 __u16 product;
875 int sif = 0;
876
Hans de Goededcef3232008-07-10 10:40:53 -0300877 /* nctrls depends upon the sensor, so we use a per cam copy */
878 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
879 gspca_dev->sd_desc = &sd->sd_desc;
880
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300881 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300882 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300883 sd->autogain = AUTOGAIN_DEF; /* default is autogain active */
Hans de Goededcef3232008-07-10 10:40:53 -0300884
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300885 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300886/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300887/* case 0x0c45: * Sonix */
888 switch (product) {
889 case 0x6001: /* SN9C102 */
890 case 0x6005: /* SN9C101 */
891 case 0x6007: /* SN9C101 */
892 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300893 sd->sensor_has_gain = 1;
894 sd->sd_desc.nctrls = 4;
895 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300896 sif = 1;
897 break;
898 case 0x6009: /* SN9C101 */
899 case 0x600d: /* SN9C101 */
900 case 0x6029: /* SN9C101 */
901 sd->sensor = SENSOR_PAS106;
902 sif = 1;
903 break;
904 case 0x6011: /* SN9C101 - SN9C101G */
905 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300906 sd->sensor_has_gain = 1;
Hans de Goedea975a522008-07-16 15:29:11 -0300907 sd->sensor_addr = 0x60;
Hans de Goede722103e2008-07-17 10:24:47 -0300908 sd->sd_desc.nctrls = 5;
Hans de Goededcef3232008-07-10 10:40:53 -0300909 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300910 sif = 1;
911 break;
912 case 0x6019: /* SN9C101 */
913 case 0x602c: /* SN9C102 */
914 case 0x602e: /* SN9C102 */
915 sd->sensor = SENSOR_OV7630;
Hans de Goedea975a522008-07-16 15:29:11 -0300916 sd->sensor_addr = 0x21;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300917 break;
918 case 0x60b0: /* SN9C103 */
919 sd->sensor = SENSOR_OV7630_3;
Hans de Goedea975a522008-07-16 15:29:11 -0300920 sd->sensor_addr = 0x21;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300921 sd->fr_h_sz = 18; /* size of frame header */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300922 sd->sensor_has_gain = 1;
Hans de Goede12ff9122008-07-17 10:30:56 -0300923 sd->sd_desc.nctrls = 8;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300924 sd->sd_desc.dq_callback = do_autogain;
925 sd->autogain = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300926 break;
927 case 0x6024: /* SN9C102 */
928 case 0x6025: /* SN9C102 */
929 sd->sensor = SENSOR_TAS5130CXX;
930 break;
931 case 0x6028: /* SN9C102 */
932 sd->sensor = SENSOR_PAS202;
933 break;
934 case 0x602d: /* SN9C102 */
935 sd->sensor = SENSOR_HV7131R;
936 break;
937 case 0x60af: /* SN9C103 */
938 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300939 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300940 break;
941 }
942/* break; */
943/* } */
944
945 cam = &gspca_dev->cam;
946 cam->dev_name = (char *) id->driver_info;
947 cam->epaddr = 0x01;
948 if (!sif) {
949 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300950 cam->nmodes = ARRAY_SIZE(vga_mode);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300951 if (sd->sensor == SENSOR_OV7630_3) {
952 /* We only have 320x240 & 640x480 */
953 cam->cam_mode++;
954 cam->nmodes--;
955 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300956 } else {
957 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300958 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300959 }
Hans de Goededcef3232008-07-10 10:40:53 -0300960 sd->brightness = BRIGHTNESS_DEF;
961 sd->gain = GAIN_DEF;
962 sd->exposure = EXPOSURE_DEF;
Hans de Goede12ff9122008-07-17 10:30:56 -0300963 sd->freq = FREQ_DEF;
964 sd->contrast = CONTRAST_DEF;
965 sd->saturation = SATURATION_DEF;
966 sd->hue = HUE_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300967 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300968 reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300969 return 0;
970}
971
972/* this function is called at open time */
973static int sd_open(struct gspca_dev *gspca_dev)
974{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300975 reg_r(gspca_dev, 0x00);
976 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300977 return -ENODEV;
978 return 0;
979}
980
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300981static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300982{
983 int i;
984 const __u8 *data;
985 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
986
987 i = ARRAY_SIZE(pas106_data);
988 data = pas106_data[0];
989 while (--i >= 0) {
990 memcpy(&i2c1[2], data, 2);
991 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300992 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300993 PDEBUG(D_ERR, "i2c error pas106");
994 data += 2;
995 }
996}
997
998/* -- start the camera -- */
999static void sd_start(struct gspca_dev *gspca_dev)
1000{
1001 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001002 int mode, l;
1003 const __u8 *sn9c10x;
1004 __u8 reg01, reg17;
1005 __u8 reg17_19[3];
1006
Jean-Francois Moinec2446b32008-07-05 11:49:20 -03001007 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001008 switch (sd->sensor) {
1009 case SENSOR_HV7131R:
1010 sn9c10x = initHv7131;
1011 reg17_19[0] = 0x60;
1012 reg17_19[1] = (mode << 4) | 0x8a;
1013 reg17_19[2] = 0x20;
1014 break;
1015 case SENSOR_OV6650:
1016 sn9c10x = initOv6650;
1017 reg17_19[0] = 0x68;
1018 reg17_19[1] = (mode << 4) | 0x8b;
1019 reg17_19[2] = 0x20;
1020 break;
1021 case SENSOR_OV7630:
1022 sn9c10x = initOv7630;
1023 reg17_19[0] = 0x68;
1024 reg17_19[1] = (mode << 4) | COMP2;
1025 reg17_19[2] = MCK_INIT1;
1026 break;
1027 case SENSOR_OV7630_3:
1028 sn9c10x = initOv7630_3;
1029 reg17_19[0] = 0x68;
1030 reg17_19[1] = (mode << 4) | COMP2;
1031 reg17_19[2] = MCK_INIT1;
1032 break;
1033 case SENSOR_PAS106:
1034 sn9c10x = initPas106;
1035 reg17_19[0] = 0x24; /* 0x28 */
1036 reg17_19[1] = (mode << 4) | COMP1;
1037 reg17_19[2] = MCK_INIT1;
1038 break;
1039 case SENSOR_PAS202:
1040 sn9c10x = initPas202;
1041 reg17_19[0] = mode ? 0x24 : 0x20;
1042 reg17_19[1] = (mode << 4) | 0x89;
1043 reg17_19[2] = 0x20;
1044 break;
1045 case SENSOR_TAS5110:
1046 sn9c10x = initTas5110;
1047 reg17_19[0] = 0x60;
1048 reg17_19[1] = (mode << 4) | 0x86;
1049 reg17_19[2] = 0x2b; /* 0xf3; */
1050 break;
1051 default:
1052/* case SENSOR_TAS5130CXX: */
1053 sn9c10x = initTas5130;
1054 reg17_19[0] = 0x60;
1055 reg17_19[1] = (mode << 4) | COMP;
1056 reg17_19[2] = mode ? 0x23 : 0x43;
1057 break;
1058 }
1059 switch (sd->sensor) {
1060 case SENSOR_OV7630:
1061 reg01 = 0x06;
1062 reg17 = 0x29;
Jean-Francois Moine1ff1e482008-07-17 09:37:57 -03001063 l = sizeof initOv7630;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001064 break;
1065 case SENSOR_OV7630_3:
1066 reg01 = 0x44;
1067 reg17 = 0x68;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -03001068 l = sizeof initOv7630_3;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001069 break;
1070 default:
1071 reg01 = sn9c10x[0];
1072 reg17 = sn9c10x[0x17 - 1];
1073 l = 0x1f;
1074 break;
1075 }
1076
1077 /* reg 0x01 bit 2 video transfert on */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001078 reg_w(gspca_dev, 0x01, &reg01, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001079 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001080 reg_w(gspca_dev, 0x17, &reg17, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001081/*fixme: for ov7630 102
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001082 reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001083 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001084 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001085 switch (sd->sensor) {
1086 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001087 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001088 sizeof hv7131_sensor_init);
1089 break;
1090 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001091 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001092 sizeof ov6650_sensor_init);
1093 break;
1094 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001095 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001096 sizeof ov7630_sensor_init_com);
1097 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001098 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001099 sizeof ov7630_sensor_init);
1100 break;
1101 case SENSOR_OV7630_3:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001102 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001103 sizeof ov7630_sensor_init_com);
1104 msleep(200);
Andoni Zubimendid87616f2008-07-17 05:35:52 -03001105 i2c_w(gspca_dev, ov7630_sensor_init_3[mode]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001106 break;
1107 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001108 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001109 break;
1110 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001111 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001112 sizeof pas202_sensor_init);
1113 break;
1114 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001115 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001116 sizeof tas5110_sensor_init);
1117 break;
1118 default:
1119/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001120 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001121 sizeof tas5130_sensor_init);
1122 break;
1123 }
Hans de Goede3647fea2008-07-15 05:36:30 -03001124 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
1125 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001126 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001127 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -03001128 /* H_start */
1129 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
1130 /* V_START */
1131 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001132 /* reset 0x17 SensorClk enable inv Clk 0x60 */
1133 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001134 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001135 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -03001136 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001137 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001138 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001139 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001140 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001141 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001142 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001143 msleep(20);
1144
Hans de Goededcef3232008-07-10 10:40:53 -03001145 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001146 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001147 setexposure(gspca_dev);
Hans de Goede66f35822008-07-16 10:16:28 -03001148 setfreq(gspca_dev);
Hans de Goede12ff9122008-07-17 10:30:56 -03001149 setsaturation(gspca_dev);
1150 sethue(gspca_dev);
1151 setcontrast(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001152
1153 sd->autogain_ignore_frames = 0;
1154 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001155}
1156
1157static void sd_stopN(struct gspca_dev *gspca_dev)
1158{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -03001159 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001160
1161 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001162 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001163}
1164
1165static void sd_stop0(struct gspca_dev *gspca_dev)
1166{
1167}
1168
1169static void sd_close(struct gspca_dev *gspca_dev)
1170{
1171}
1172
1173static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1174 struct gspca_frame *frame, /* target */
1175 unsigned char *data, /* isoc packet */
1176 int len) /* iso packet length */
1177{
Hans de Goede0d2a7222008-07-03 08:15:22 -03001178 int i;
Hans de Goededcef3232008-07-10 10:40:53 -03001179 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001180
Hans de Goedec36260ee2008-07-16 09:56:07 -03001181 /* frames start with:
1182 * ff ff 00 c4 c4 96 synchro
1183 * 00 (unknown)
1184 * xx (frame sequence / size / compression)
1185 * (xx) (idem - extra byte for sn9c103)
1186 * ll mm brightness sum inside auto exposure
1187 * ll mm brightness sum outside auto exposure
1188 * (xx xx xx xx xx) audio values for snc103
1189 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001190 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -03001191 for (i = 0; i < len - 6; i++) {
1192 if (data[0 + i] == 0xff
1193 && data[1 + i] == 0xff
1194 && data[2 + i] == 0x00
1195 && data[3 + i] == 0xc4
1196 && data[4 + i] == 0xc4
1197 && data[5 + i] == 0x96) { /* start of frame */
1198 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
1199 frame, data, 0);
Hans de Goedec36260ee2008-07-16 09:56:07 -03001200 if (len - i < sd->fr_h_sz) {
1201 atomic_set(&sd->avg_lum, -1);
1202 PDEBUG(D_STREAM, "packet too short to"
1203 " get avg brightness");
1204 } else if (sd->fr_h_sz == 12) {
1205 atomic_set(&sd->avg_lum,
1206 data[i + 8] +
Hans de Goededcef3232008-07-10 10:40:53 -03001207 (data[i + 9] << 8));
1208 } else {
Hans de Goedec36260ee2008-07-16 09:56:07 -03001209 atomic_set(&sd->avg_lum,
1210 data[i + 9] +
1211 (data[i + 10] << 8));
Hans de Goededcef3232008-07-10 10:40:53 -03001212 }
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -03001213 data += i + sd->fr_h_sz;
1214 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001215 gspca_frame_add(gspca_dev, FIRST_PACKET,
1216 frame, data, len);
1217 return;
1218 }
1219 }
1220 }
1221 gspca_frame_add(gspca_dev, INTER_PACKET,
1222 frame, data, len);
1223}
1224
1225static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1226{
1227 struct sd *sd = (struct sd *) gspca_dev;
1228
1229 sd->brightness = val;
1230 if (gspca_dev->streaming)
1231 setbrightness(gspca_dev);
1232 return 0;
1233}
1234
1235static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1236{
1237 struct sd *sd = (struct sd *) gspca_dev;
1238
1239 *val = sd->brightness;
1240 return 0;
1241}
1242
Hans de Goededcef3232008-07-10 10:40:53 -03001243static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001244{
1245 struct sd *sd = (struct sd *) gspca_dev;
1246
Hans de Goededcef3232008-07-10 10:40:53 -03001247 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001248 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001249 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001250 return 0;
1251}
1252
Hans de Goededcef3232008-07-10 10:40:53 -03001253static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001254{
1255 struct sd *sd = (struct sd *) gspca_dev;
1256
Hans de Goededcef3232008-07-10 10:40:53 -03001257 *val = sd->gain;
1258 return 0;
1259}
1260
1261static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1262{
1263 struct sd *sd = (struct sd *) gspca_dev;
1264
1265 sd->exposure = val;
1266 if (gspca_dev->streaming)
1267 setexposure(gspca_dev);
1268 return 0;
1269}
1270
1271static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1272{
1273 struct sd *sd = (struct sd *) gspca_dev;
1274
1275 *val = sd->exposure;
1276 return 0;
1277}
1278
1279static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1280{
1281 struct sd *sd = (struct sd *) gspca_dev;
1282
1283 sd->autogain = val;
1284 /* when switching to autogain set defaults to make sure
1285 we are on a valid point of the autogain gain /
1286 exposure knee graph, and give this change time to
1287 take effect before doing autogain. */
1288 if (sd->autogain) {
1289 sd->exposure = EXPOSURE_DEF;
1290 sd->gain = GAIN_DEF;
1291 if (gspca_dev->streaming) {
1292 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1293 setexposure(gspca_dev);
1294 setgain(gspca_dev);
1295 }
1296 }
1297
1298 return 0;
1299}
1300
1301static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1302{
1303 struct sd *sd = (struct sd *) gspca_dev;
1304
1305 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001306 return 0;
1307}
1308
Hans de Goede66f35822008-07-16 10:16:28 -03001309static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1310{
1311 struct sd *sd = (struct sd *) gspca_dev;
1312
1313 sd->freq = val;
1314 if (gspca_dev->streaming)
1315 setfreq(gspca_dev);
1316 return 0;
1317}
1318
1319static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1320{
1321 struct sd *sd = (struct sd *) gspca_dev;
1322
1323 *val = sd->freq;
1324 return 0;
1325}
1326
Hans de Goede12ff9122008-07-17 10:30:56 -03001327static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)
1328{
1329 struct sd *sd = (struct sd *) gspca_dev;
1330
1331 sd->saturation = val;
1332 if (gspca_dev->streaming)
1333 setsaturation(gspca_dev);
1334 return 0;
1335}
1336
1337static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)
1338{
1339 struct sd *sd = (struct sd *) gspca_dev;
1340
1341 *val = sd->saturation;
1342 return 0;
1343}
1344
1345static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
1346{
1347 struct sd *sd = (struct sd *) gspca_dev;
1348
1349 sd->hue = val;
1350 if (gspca_dev->streaming)
1351 sethue(gspca_dev);
1352 return 0;
1353}
1354
1355static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
1356{
1357 struct sd *sd = (struct sd *) gspca_dev;
1358
1359 *val = sd->hue;
1360 return 0;
1361}
1362
1363static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1364{
1365 struct sd *sd = (struct sd *) gspca_dev;
1366
1367 sd->contrast = val;
1368 if (gspca_dev->streaming)
1369 setcontrast(gspca_dev);
1370 return 0;
1371}
1372
1373static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1374{
1375 struct sd *sd = (struct sd *) gspca_dev;
1376
1377 *val = sd->contrast;
1378 return 0;
1379}
1380
Hans de Goede66f35822008-07-16 10:16:28 -03001381static int sd_querymenu(struct gspca_dev *gspca_dev,
1382 struct v4l2_querymenu *menu)
1383{
1384 switch (menu->id) {
1385 case V4L2_CID_POWER_LINE_FREQUENCY:
1386 switch (menu->index) {
1387 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1388 strcpy((char *) menu->name, "NoFliker");
1389 return 0;
1390 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1391 strcpy((char *) menu->name, "50 Hz");
1392 return 0;
1393 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1394 strcpy((char *) menu->name, "60 Hz");
1395 return 0;
1396 }
1397 break;
1398 }
1399 return -EINVAL;
1400}
1401
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001402/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001403static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001404 .name = MODULE_NAME,
1405 .ctrls = sd_ctrls,
1406 .nctrls = ARRAY_SIZE(sd_ctrls),
1407 .config = sd_config,
1408 .open = sd_open,
1409 .start = sd_start,
1410 .stopN = sd_stopN,
1411 .stop0 = sd_stop0,
1412 .close = sd_close,
1413 .pkt_scan = sd_pkt_scan,
Hans de Goede66f35822008-07-16 10:16:28 -03001414 .querymenu = sd_querymenu,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001415};
1416
1417/* -- module initialisation -- */
1418#define DVNM(name) .driver_info = (kernel_ulong_t) name
1419static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001420#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001421 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1422 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1423 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1424 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1425 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Hans de Goede5de39b22008-07-17 10:34:28 -03001426#endif
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001427 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Hans de Goede5de39b22008-07-17 10:34:28 -03001428#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001429 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1430 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1431 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1432 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1433 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1434 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1435 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1436 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1437 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1438 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001439#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001440 {}
1441};
1442MODULE_DEVICE_TABLE(usb, device_table);
1443
1444/* -- device connect -- */
1445static int sd_probe(struct usb_interface *intf,
1446 const struct usb_device_id *id)
1447{
1448 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1449 THIS_MODULE);
1450}
1451
1452static struct usb_driver sd_driver = {
1453 .name = MODULE_NAME,
1454 .id_table = device_table,
1455 .probe = sd_probe,
1456 .disconnect = gspca_disconnect,
1457};
1458
1459/* -- module insert / remove -- */
1460static int __init sd_mod_init(void)
1461{
1462 if (usb_register(&sd_driver) < 0)
1463 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001464 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001465 return 0;
1466}
1467static void __exit sd_mod_exit(void)
1468{
1469 usb_deregister(&sd_driver);
1470 PDEBUG(D_PROBE, "deregistered");
1471}
1472
1473module_init(sd_mod_init);
1474module_exit(sd_mod_exit);