blob: 5b3490ad661aabf97ad095b43a157350f37f528c [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 Moine100f7f22008-07-17 09:41:03 -030027#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 8)
28static const char version[] = "2.1.8";
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
Hans de Goedead5ef80d2008-07-14 10:11:42 -030042 unsigned char gain;
43 unsigned char 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;
Hans de Goede66f35822008-07-16 10:16:28 -030047 unsigned char freq; /* light freq filter setting */
Hans de Goede12ff9122008-07-17 10:30:56 -030048 unsigned char saturation;
49 unsigned char hue;
50 unsigned char contrast;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030051
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -030052 unsigned char fr_h_sz; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030053 char sensor; /* Type of image sensor chip */
54#define SENSOR_HV7131R 0
55#define SENSOR_OV6650 1
56#define SENSOR_OV7630 2
57#define SENSOR_OV7630_3 3
58#define SENSOR_PAS106 4
59#define SENSOR_PAS202 5
60#define SENSOR_TAS5110 6
61#define SENSOR_TAS5130CXX 7
Hans de Goedea975a522008-07-16 15:29:11 -030062 char sensor_has_gain;
63 __u8 sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030064};
65
66#define COMP2 0x8f
67#define COMP 0xc7 /* 0x87 //0x07 */
68#define COMP1 0xc9 /* 0x89 //0x09 */
69
70#define MCK_INIT 0x63
71#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
72
73#define SYS_CLK 0x04
74
Hans de Goededcef3232008-07-10 10:40:53 -030075/* We calculate the autogain at the end of the transfer of a frame, at this
76 moment a frame with the old settings is being transmitted, and a frame is
77 being captured with the old settings. So if we adjust the autogain we must
78 ignore atleast the 2 next frames for the new settings to come into effect
79 before doing any other adjustments */
80#define AUTOGAIN_IGNORE_FRAMES 3
Hans de Goedead5ef80d2008-07-14 10:11:42 -030081#define AUTOGAIN_DEADZONE 1000
Hans de Goededcef3232008-07-10 10:40:53 -030082#define DESIRED_AVG_LUM 7000
83
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030084/* V4L2 controls supported by the driver */
85static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
86static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goededcef3232008-07-10 10:40:53 -030087static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
88static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
89static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
90static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
91static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
92static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede66f35822008-07-16 10:16:28 -030093static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
94static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede12ff9122008-07-17 10:30:56 -030095static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val);
96static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);
97static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
98static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
99static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
100static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300101
102static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300103 {
104 {
105 .id = V4L2_CID_BRIGHTNESS,
106 .type = V4L2_CTRL_TYPE_INTEGER,
107 .name = "Brightness",
108 .minimum = 0,
109 .maximum = 255,
110 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -0300111#define BRIGHTNESS_DEF 127
112 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300113 },
114 .set = sd_setbrightness,
115 .get = sd_getbrightness,
116 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300117 {
118 {
Hans de Goededcef3232008-07-10 10:40:53 -0300119 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300120 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300121 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300122 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300123 .maximum = 255,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300124 .step = 1,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300125#define GAIN_DEF 127
126#define GAIN_KNEE 200
Hans de Goededcef3232008-07-10 10:40:53 -0300127 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300128 },
Hans de Goededcef3232008-07-10 10:40:53 -0300129 .set = sd_setgain,
130 .get = sd_getgain,
131 },
Hans de Goededcef3232008-07-10 10:40:53 -0300132 {
133 {
134 .id = V4L2_CID_EXPOSURE,
135 .type = V4L2_CTRL_TYPE_INTEGER,
136 .name = "Exposure",
Hans de Goedef4d52022008-07-15 09:36:42 -0300137#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
138#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
Hans de Goededcef3232008-07-10 10:40:53 -0300139 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300140 .maximum = 255,
Hans de Goededcef3232008-07-10 10:40:53 -0300141 .step = 1,
142 .default_value = EXPOSURE_DEF,
143 .flags = 0,
144 },
145 .set = sd_setexposure,
146 .get = sd_getexposure,
147 },
Hans de Goededcef3232008-07-10 10:40:53 -0300148 {
149 {
150 .id = V4L2_CID_AUTOGAIN,
151 .type = V4L2_CTRL_TYPE_BOOLEAN,
152 .name = "Automatic Gain (and Exposure)",
153 .minimum = 0,
154 .maximum = 1,
155 .step = 1,
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300156#define AUTOGAIN_DEF 1
157 .default_value = AUTOGAIN_DEF,
Hans de Goededcef3232008-07-10 10:40:53 -0300158 .flags = 0,
159 },
160 .set = sd_setautogain,
161 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300162 },
Hans de Goede66f35822008-07-16 10:16:28 -0300163 {
164 {
165 .id = V4L2_CID_POWER_LINE_FREQUENCY,
166 .type = V4L2_CTRL_TYPE_MENU,
167 .name = "Light frequency filter",
168 .minimum = 0,
169 .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
170 .step = 1,
171#define FREQ_DEF 1
172 .default_value = FREQ_DEF,
173 },
174 .set = sd_setfreq,
175 .get = sd_getfreq,
176 },
Hans de Goede12ff9122008-07-17 10:30:56 -0300177 {
178 {
179 .id = V4L2_CID_SATURATION,
180 .type = V4L2_CTRL_TYPE_INTEGER,
181 .name = "Saturation",
182 .minimum = 0,
183 .maximum = 255,
184 .step = 1,
185#define SATURATION_DEF 127
186 .default_value = SATURATION_DEF,
187 },
188 .set = sd_setsaturation,
189 .get = sd_getsaturation,
190 },
191 {
192 {
193 .id = V4L2_CID_HUE,
194 .type = V4L2_CTRL_TYPE_INTEGER,
195 .name = "Hue",
196 .minimum = 0,
197 .maximum = 255,
198 .step = 1,
199#define HUE_DEF 127
200 .default_value = HUE_DEF,
201 },
202 .set = sd_sethue,
203 .get = sd_gethue,
204 },
205 {
206 {
207 .id = V4L2_CID_CONTRAST,
208 .type = V4L2_CTRL_TYPE_INTEGER,
209 .name = "Contrast",
210 .minimum = 0,
211 .maximum = 255,
212 .step = 1,
213#define CONTRAST_DEF 127
214 .default_value = CONTRAST_DEF,
215 },
216 .set = sd_setcontrast,
217 .get = sd_getcontrast,
218 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300219};
220
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300221static struct v4l2_pix_format vga_mode[] = {
222 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
223 .bytesperline = 160,
224 .sizeimage = 160 * 120,
225 .colorspace = V4L2_COLORSPACE_SRGB,
226 .priv = 2},
227 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
228 .bytesperline = 320,
229 .sizeimage = 320 * 240,
230 .colorspace = V4L2_COLORSPACE_SRGB,
231 .priv = 1},
232 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
233 .bytesperline = 640,
234 .sizeimage = 640 * 480,
235 .colorspace = V4L2_COLORSPACE_SRGB,
236 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300237};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300238static struct v4l2_pix_format sif_mode[] = {
239 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
240 .bytesperline = 176,
241 .sizeimage = 176 * 144,
242 .colorspace = V4L2_COLORSPACE_SRGB,
243 .priv = 1},
244 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
245 .bytesperline = 352,
246 .sizeimage = 352 * 288,
247 .colorspace = V4L2_COLORSPACE_SRGB,
248 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300249};
250
251static const __u8 probe_ov7630[] = {0x08, 0x44};
252
253static const __u8 initHv7131[] = {
254 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
255 0x00, 0x00,
256 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
257 0x28, 0x1e, 0x60, 0x8a, 0x20,
258 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
259};
260static const __u8 hv7131_sensor_init[][8] = {
261 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
262 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
263 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
264 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
265 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
266};
267static const __u8 initOv6650[] = {
268 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
269 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
270 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
271 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
272};
273static const __u8 ov6650_sensor_init[][8] =
274{
275 /* Bright, contrast, etc are set througth SCBB interface.
276 * AVCAP on win2 do not send any data on this controls. */
277 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300278
279 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300280 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300281 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300282 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300283 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300284 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
285/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
286 * THIS SET GREEN SCREEN
287 * (pixels could be innverted in decode kind of "brg",
288 * but blue wont be there. Avoid this data ... */
289 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
290 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
291 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goede722103e2008-07-17 10:24:47 -0300292 /* Enable rgb brightness control */
293 {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
294 /* HDG: Note windows uses the line below, which sets both register 0x60
295 and 0x61 I believe these registers of the ov6650 are identical as
296 those of the ov7630, because if this is true the windows settings
297 add a bit additional red gain and a lot additional blue gain, which
298 matches my findings that the windows settings make blue much too
299 blue and red a little too red.
300 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
Hans de Goededcef3232008-07-10 10:40:53 -0300301 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300302 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
303 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300304};
Hans de Goededcef3232008-07-10 10:40:53 -0300305
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300306static const __u8 initOv7630[] = {
307 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
308 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
309 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
310 0x28, 0x1e, /* H & V sizes r15 .. r16 */
311 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
312 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
313};
314static const __u8 initOv7630_3[] = {
315 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
316 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300317 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300318 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300319 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
320 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
321 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
322 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300323};
324static const __u8 ov7630_sensor_init_com[][8] = {
325 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
326 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
327/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300328 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300329 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
330 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
331 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
332 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
333 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
334 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
335 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
Andoni Zubimendi794af522008-07-16 08:33:14 -0300336 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
337/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300338 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
339 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
340 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
341 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
342 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
343 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
344};
345static const __u8 ov7630_sensor_init[][8] = {
346 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
347 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
348 {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
349 {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
350 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
351};
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300352static const __u8 ov7630_sensor_init_3[][8] = {
353 {0xa0, 0x21, 0x2a, 0xa0, 0x00, 0x00, 0x00, 0x10},
354 {0xa0, 0x21, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x10},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300355};
356
357static const __u8 initPas106[] = {
358 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
359 0x00, 0x00,
360 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
361 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
362 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
363};
364/* compression 0x86 mckinit1 0x2b */
365static const __u8 pas106_data[][2] = {
366 {0x02, 0x04}, /* Pixel Clock Divider 6 */
367 {0x03, 0x13}, /* Frame Time MSB */
368/* {0x03, 0x12}, * Frame Time MSB */
369 {0x04, 0x06}, /* Frame Time LSB */
370/* {0x04, 0x05}, * Frame Time LSB */
371 {0x05, 0x65}, /* Shutter Time Line Offset */
372/* {0x05, 0x6d}, * Shutter Time Line Offset */
373/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
374 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
375 {0x07, 0xc1}, /* Black Level Subtract Sign */
376/* {0x07, 0x00}, * Black Level Subtract Sign */
377 {0x08, 0x06}, /* Black Level Subtract Level */
378 {0x08, 0x06}, /* Black Level Subtract Level */
379/* {0x08, 0x01}, * Black Level Subtract Level */
380 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
381 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
382 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
383 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
384 {0x0d, 0x00}, /* Color GainH Pixel */
385 {0x0e, 0x0e}, /* Global Gain */
386 {0x0f, 0x00}, /* Contrast */
387 {0x10, 0x06}, /* H&V synchro polarity */
388 {0x11, 0x06}, /* ?default */
389 {0x12, 0x06}, /* DAC scale */
390 {0x14, 0x02}, /* ?default */
391 {0x13, 0x01}, /* Validate Settings */
392};
393static const __u8 initPas202[] = {
394 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
395 0x00, 0x00,
396 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
397 0x28, 0x1e, 0x28, 0x89, 0x30,
398 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
399};
400static const __u8 pas202_sensor_init[][8] = {
401 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
402 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
403 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
404 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
405 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
406 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
407 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
408 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
409 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
410 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
411 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
412 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
413
414 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
415 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
416 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
417 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
418 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
419 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
420 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
421 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
422};
423
424static const __u8 initTas5110[] = {
425 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
426 0x00, 0x00,
427 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
428 0x16, 0x12, 0x60, 0x86, 0x2b,
429 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
430};
431static const __u8 tas5110_sensor_init[][8] = {
432 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
433 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
434 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
435};
436
437static const __u8 initTas5130[] = {
438 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
439 0x00, 0x00,
440 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
441 0x28, 0x1e, 0x60, COMP, MCK_INIT,
442 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
443};
444static const __u8 tas5130_sensor_init[][8] = {
445/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
446 * shutter 0x47 short exposure? */
447 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
448 /* shutter 0x01 long exposure */
449 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
450};
451
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300452/* get one byte in gspca_dev->usb_buf */
453static void reg_r(struct gspca_dev *gspca_dev,
454 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300455{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300456 usb_control_msg(gspca_dev->dev,
457 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300458 0, /* request */
459 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
460 value,
461 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300462 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300463 500);
464}
465
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300466static void reg_w(struct gspca_dev *gspca_dev,
467 __u16 value,
468 const __u8 *buffer,
469 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300470{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300471#ifdef CONFIG_VIDEO_ADV_DEBUG
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300472 if (len > sizeof gspca_dev->usb_buf) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300473 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
474 return;
475 }
476#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300477 memcpy(gspca_dev->usb_buf, buffer, len);
478 usb_control_msg(gspca_dev->dev,
479 usb_sndctrlpipe(gspca_dev->dev, 0),
480 0x08, /* request */
481 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
482 value,
483 0, /* index */
484 gspca_dev->usb_buf, len,
485 500);
486}
487
488static void reg_w_big(struct gspca_dev *gspca_dev,
489 __u16 value,
490 const __u8 *buffer,
491 int len)
492{
493 __u8 *tmpbuf;
494
495 tmpbuf = kmalloc(len, GFP_KERNEL);
Hans de Goede0d2a7222008-07-03 08:15:22 -0300496 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300497 usb_control_msg(gspca_dev->dev,
498 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300499 0x08, /* request */
500 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
501 value,
502 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300503 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300504 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300505 kfree(tmpbuf);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506}
507
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300508static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300509{
510 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300511
512 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300513 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300514 while (retry--) {
515 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300516 reg_r(gspca_dev, 0x08);
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300517 if (gspca_dev->usb_buf[0] & 0x04) {
518 if (gspca_dev->usb_buf[0] & 0x08)
519 return -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300520 return 0;
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300521 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300522 }
523 return -1;
524}
525
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300526static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300527 const __u8 buffer[][8], int len)
528{
529 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300530 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300531 len -= 8;
532 if (len <= 0)
533 break;
534 buffer++;
535 }
536}
537
538static void setbrightness(struct gspca_dev *gspca_dev)
539{
540 struct sd *sd = (struct sd *) gspca_dev;
541 __u8 value;
542
543 switch (sd->sensor) {
Hans de Goedea975a522008-07-16 15:29:11 -0300544 case SENSOR_OV6650:
Andoni Zubimendi794af522008-07-16 08:33:14 -0300545 case SENSOR_OV7630_3:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300546 case SENSOR_OV7630: {
547 __u8 i2cOV[] =
Hans de Goedea975a522008-07-16 15:29:11 -0300548 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300549
550 /* change reg 0x06 */
Hans de Goedea975a522008-07-16 15:29:11 -0300551 i2cOV[1] = sd->sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300552 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300553 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300554 goto err;
555 break;
556 }
557 case SENSOR_PAS106: {
558 __u8 i2c1[] =
559 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
560
561 i2c1[3] = sd->brightness >> 3;
562 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300563 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300564 goto err;
565 i2c1[3] = 0x01;
566 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300567 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300568 goto err;
569 break;
570 }
571 case SENSOR_PAS202: {
572 /* __u8 i2cpexpo1[] =
573 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
574 __u8 i2cpexpo[] =
575 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
576 __u8 i2cp202[] =
577 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
578 static __u8 i2cpdoit[] =
579 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
580
581 /* change reg 0x10 */
582 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300583/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300584 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300585/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300586 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300587 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300588 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300589 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300590 goto err;
591 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300592 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300594 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300595 goto err;
596 break;
597 }
Hans de Goededcef3232008-07-10 10:40:53 -0300598 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300599 __u8 i2c[] =
600 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
601
602 value = 0xff - sd->brightness;
603 i2c[4] = value;
604 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300605 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300606 goto err;
607 break;
608 }
Hans de Goededcef3232008-07-10 10:40:53 -0300609 case SENSOR_TAS5110:
610 /* FIXME figure out howto control brightness on TAS5110 */
611 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300612 }
613 return;
614err:
615 PDEBUG(D_ERR, "i2c error brightness");
616}
Hans de Goededcef3232008-07-10 10:40:53 -0300617
618static void setsensorgain(struct gspca_dev *gspca_dev)
619{
620 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea975a522008-07-16 15:29:11 -0300621 unsigned char gain = sd->gain;
Hans de Goededcef3232008-07-10 10:40:53 -0300622
623 switch (sd->sensor) {
624
625 case SENSOR_TAS5110: {
626 __u8 i2c[] =
627 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
628
Hans de Goedea975a522008-07-16 15:29:11 -0300629 i2c[4] = 255 - gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300630 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300631 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300632 break;
633 }
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300634
Hans de Goedea975a522008-07-16 15:29:11 -0300635 case SENSOR_OV6650:
636 gain >>= 1;
637 /* fall thru */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300638 case SENSOR_OV7630_3: {
Hans de Goedea975a522008-07-16 15:29:11 -0300639 __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Andoni Zubimendi794af522008-07-16 08:33:14 -0300640
Hans de Goedea975a522008-07-16 15:29:11 -0300641 i2c[1] = sd->sensor_addr;
642 i2c[3] = gain >> 2;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300643 if (i2c_w(gspca_dev, i2c) < 0)
644 goto err;
645 break;
646 }
Hans de Goededcef3232008-07-10 10:40:53 -0300647 }
648 return;
649err:
650 PDEBUG(D_ERR, "i2c error gain");
651}
652
653static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300654{
655 struct sd *sd = (struct sd *) gspca_dev;
656 __u8 gain;
657 __u8 rgb_value;
658
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300659 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300660
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300661 /* red and blue gain */
662 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300663 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300664 /* green gain */
665 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300666 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300667
668 if (sd->sensor_has_gain)
669 setsensorgain(gspca_dev);
670}
671
672static void setexposure(struct gspca_dev *gspca_dev)
673{
674 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300675
676 switch (sd->sensor) {
677 case SENSOR_TAS5110: {
678 __u8 reg;
679
680 /* register 19's high nibble contains the sn9c10x clock divider
681 The high nibble configures the no fps according to the
682 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300683 reg = 120 * sd->exposure / 1000;
684 if (reg < 2)
685 reg = 2;
686 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300687 reg = 15;
688 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300689 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300690 break;
691 }
Hans de Goedea975a522008-07-16 15:29:11 -0300692 case SENSOR_OV6650:
693 case SENSOR_OV7630_3: {
694 /* The ov6650 / ov7630 have 2 registers which both influence
695 exposure, register 11, whose low nibble sets the nr off fps
Hans de Goedef4d52022008-07-15 09:36:42 -0300696 according to: fps = 30 / (low_nibble + 1)
697
698 The fps configures the maximum exposure setting, but it is
699 possible to use less exposure then what the fps maximum
700 allows by setting register 10. register 10 configures the
701 actual exposure as quotient of the full exposure, with 0
702 being no exposure at all (not very usefull) and reg10_max
703 being max exposure possible at that framerate.
704
705 The code maps our 0 - 510 ms exposure ctrl to these 2
706 registers, trying to keep fps as high as possible.
707 */
Hans de Goedea975a522008-07-16 15:29:11 -0300708 __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
Hans de Goedef4d52022008-07-15 09:36:42 -0300709 int reg10, reg11;
Hans de Goede66f35822008-07-16 10:16:28 -0300710 /* ov6645 datasheet says reg10_max is 9a, but that uses
711 tline * 2 * reg10 as formula for calculating texpo, the
712 ov6650 probably uses the same formula as the 7730 which uses
713 tline * 4 * reg10, which explains why the reg10max we've
714 found experimentally for the ov6650 is exactly half that of
Hans de Goedea975a522008-07-16 15:29:11 -0300715 the ov6645. The ov7630 datasheet says the max is 0x41. */
Hans de Goede722103e2008-07-17 10:24:47 -0300716 const int reg10_max = (sd->sensor == SENSOR_OV6650)
717 ? 0x4d : 0x41;
Hans de Goedef4d52022008-07-15 09:36:42 -0300718
719 reg11 = (60 * sd->exposure + 999) / 1000;
720 if (reg11 < 1)
721 reg11 = 1;
722 else if (reg11 > 16)
723 reg11 = 16;
724
725 /* frame exposure time in ms = 1000 * reg11 / 30 ->
726 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
727 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
Hans de Goedea975a522008-07-16 15:29:11 -0300728
729 /* Don't allow this to get below 10 when using autogain, the
730 steps become very large (relatively) when below 10 causing
731 the image to oscilate from much too dark, to much too bright
732 and back again. */
733 if (sd->autogain && reg10 < 10)
734 reg10 = 10;
Hans de Goedef4d52022008-07-15 09:36:42 -0300735 else if (reg10 > reg10_max)
736 reg10 = reg10_max;
737
738 /* Write reg 10 and reg11 low nibble */
Hans de Goedea975a522008-07-16 15:29:11 -0300739 i2c[1] = sd->sensor_addr;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300740 i2c[3] = reg10;
741 i2c[4] |= reg11 - 1;
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300742 if (sd->sensor == SENSOR_OV7630_3) {
743 __u8 reg76 = reg10 & 0x03;
744 __u8 i2c_reg76[] = {0xa0, 0x21, 0x76, 0x00,
745 0x00, 0x00, 0x00, 0x10};
746 reg10 >>= 2;
747 i2c_reg76[3] = reg76;
748 if (i2c_w(gspca_dev, i2c_reg76) < 0)
749 PDEBUG(D_ERR, "i2c error exposure");
750 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300751 if (i2c_w(gspca_dev, i2c) < 0)
752 PDEBUG(D_ERR, "i2c error exposure");
753 break;
754 }
Hans de Goededcef3232008-07-10 10:40:53 -0300755 }
756}
757
Hans de Goede66f35822008-07-16 10:16:28 -0300758static void setfreq(struct gspca_dev *gspca_dev)
759{
760 struct sd *sd = (struct sd *) gspca_dev;
761
762 switch (sd->sensor) {
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300763 case SENSOR_OV6650:
764 case SENSOR_OV7630_3: {
Hans de Goede66f35822008-07-16 10:16:28 -0300765 /* Framerate adjust register for artificial light 50 hz flicker
766 compensation, identical to ov6630 0x2b register, see ov6630
767 datasheet.
768 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300769 __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goede66f35822008-07-16 10:16:28 -0300770 switch (sd->freq) {
771 default:
772/* case 0: * no filter*/
773/* case 2: * 60 hz */
774 i2c[3] = 0;
775 break;
776 case 1: /* 50 hz */
Hans de Goede722103e2008-07-17 10:24:47 -0300777 i2c[3] = (sd->sensor == SENSOR_OV6650)
778 ? 0x4f : 0x8a;
Hans de Goede66f35822008-07-16 10:16:28 -0300779 break;
780 }
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300781 i2c[1] = sd->sensor_addr;
Hans de Goede66f35822008-07-16 10:16:28 -0300782 if (i2c_w(gspca_dev, i2c) < 0)
783 PDEBUG(D_ERR, "i2c error setfreq");
784 break;
785 }
786 }
787}
788
Hans de Goede12ff9122008-07-17 10:30:56 -0300789static void setsaturation(struct gspca_dev *gspca_dev)
790{
791 struct sd *sd = (struct sd *) gspca_dev;
792
793 switch (sd->sensor) {
794/* case SENSOR_OV6650: */
795 case SENSOR_OV7630_3:
796 case SENSOR_OV7630: {
797 __u8 i2c[] = {0xa0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10};
798 i2c[1] = sd->sensor_addr;
799 i2c[3] = sd->saturation & 0xf0;
800 if (i2c_w(gspca_dev, i2c) < 0)
801 PDEBUG(D_ERR, "i2c error setsaturation");
802 else
803 PDEBUG(D_CONF, "saturation set to: %d",
804 (int)sd->saturation);
805 break;
806 }
807 }
808}
809
810static void sethue(struct gspca_dev *gspca_dev)
811{
812 struct sd *sd = (struct sd *) gspca_dev;
813
814 switch (sd->sensor) {
815/* case SENSOR_OV6650: */
816 case SENSOR_OV7630_3:
817 case SENSOR_OV7630: {
818 __u8 i2c[] = {0xa0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10};
819 i2c[1] = sd->sensor_addr;
820 i2c[3] = 0x20 | (sd->hue >> 3);
821 if (i2c_w(gspca_dev, i2c) < 0)
822 PDEBUG(D_ERR, "i2c error setsaturation");
823 else
824 PDEBUG(D_CONF, "hue set to: %d", (int)sd->hue);
825 break;
826 }
827 }
828}
829
830static void setcontrast(struct gspca_dev *gspca_dev)
831{
832 struct sd *sd = (struct sd *) gspca_dev;
833
834 switch (sd->sensor) {
835/* case SENSOR_OV6650: */
836 case SENSOR_OV7630_3:
837 case SENSOR_OV7630: {
838 __u8 i2c[] = {0xa0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10};
839 i2c[1] = sd->sensor_addr;
840 i2c[3] = 0x20 | (sd->contrast >> 3);
841 if (i2c_w(gspca_dev, i2c) < 0)
842 PDEBUG(D_ERR, "i2c error setcontrast");
843 else
844 PDEBUG(D_CONF, "contrast set to: %d",
845 (int)sd->contrast);
846 break;
847 }
848 }
849}
850
Hans de Goededcef3232008-07-10 10:40:53 -0300851
852static void do_autogain(struct gspca_dev *gspca_dev)
853{
854 struct sd *sd = (struct sd *) gspca_dev;
855 int avg_lum = atomic_read(&sd->avg_lum);
856
857 if (avg_lum == -1)
858 return;
859
860 if (sd->autogain_ignore_frames > 0)
861 sd->autogain_ignore_frames--;
862 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
863 sd->brightness * DESIRED_AVG_LUM / 127,
Hans de Goedea975a522008-07-16 15:29:11 -0300864 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
865 PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
866 (int)sd->gain, (int)sd->exposure);
Hans de Goededcef3232008-07-10 10:40:53 -0300867 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Hans de Goedea975a522008-07-16 15:29:11 -0300868 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300869}
870
871/* this function is called at probe time */
872static int sd_config(struct gspca_dev *gspca_dev,
873 const struct usb_device_id *id)
874{
875 struct sd *sd = (struct sd *) gspca_dev;
876 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300877 __u16 product;
878 int sif = 0;
879
Hans de Goededcef3232008-07-10 10:40:53 -0300880 /* nctrls depends upon the sensor, so we use a per cam copy */
881 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
882 gspca_dev->sd_desc = &sd->sd_desc;
883
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300884 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300885 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300886 sd->autogain = AUTOGAIN_DEF; /* default is autogain active */
Hans de Goededcef3232008-07-10 10:40:53 -0300887
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300888 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300889/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300890/* case 0x0c45: * Sonix */
891 switch (product) {
892 case 0x6001: /* SN9C102 */
893 case 0x6005: /* SN9C101 */
894 case 0x6007: /* SN9C101 */
895 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300896 sd->sensor_has_gain = 1;
897 sd->sd_desc.nctrls = 4;
898 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300899 sif = 1;
900 break;
901 case 0x6009: /* SN9C101 */
902 case 0x600d: /* SN9C101 */
903 case 0x6029: /* SN9C101 */
904 sd->sensor = SENSOR_PAS106;
905 sif = 1;
906 break;
907 case 0x6011: /* SN9C101 - SN9C101G */
908 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300909 sd->sensor_has_gain = 1;
Hans de Goedea975a522008-07-16 15:29:11 -0300910 sd->sensor_addr = 0x60;
Hans de Goede722103e2008-07-17 10:24:47 -0300911 sd->sd_desc.nctrls = 5;
Hans de Goededcef3232008-07-10 10:40:53 -0300912 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300913 sif = 1;
914 break;
915 case 0x6019: /* SN9C101 */
916 case 0x602c: /* SN9C102 */
917 case 0x602e: /* SN9C102 */
918 sd->sensor = SENSOR_OV7630;
Hans de Goedea975a522008-07-16 15:29:11 -0300919 sd->sensor_addr = 0x21;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300920 break;
921 case 0x60b0: /* SN9C103 */
922 sd->sensor = SENSOR_OV7630_3;
Hans de Goedea975a522008-07-16 15:29:11 -0300923 sd->sensor_addr = 0x21;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300924 sd->fr_h_sz = 18; /* size of frame header */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300925 sd->sensor_has_gain = 1;
Hans de Goede12ff9122008-07-17 10:30:56 -0300926 sd->sd_desc.nctrls = 8;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300927 sd->sd_desc.dq_callback = do_autogain;
928 sd->autogain = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300929 break;
930 case 0x6024: /* SN9C102 */
931 case 0x6025: /* SN9C102 */
932 sd->sensor = SENSOR_TAS5130CXX;
933 break;
934 case 0x6028: /* SN9C102 */
935 sd->sensor = SENSOR_PAS202;
936 break;
937 case 0x602d: /* SN9C102 */
938 sd->sensor = SENSOR_HV7131R;
939 break;
940 case 0x60af: /* SN9C103 */
941 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300942 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300943 break;
944 }
945/* break; */
946/* } */
947
948 cam = &gspca_dev->cam;
949 cam->dev_name = (char *) id->driver_info;
950 cam->epaddr = 0x01;
951 if (!sif) {
952 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300953 cam->nmodes = ARRAY_SIZE(vga_mode);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300954 if (sd->sensor == SENSOR_OV7630_3) {
955 /* We only have 320x240 & 640x480 */
956 cam->cam_mode++;
957 cam->nmodes--;
958 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300959 } else {
960 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300961 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300962 }
Hans de Goededcef3232008-07-10 10:40:53 -0300963 sd->brightness = BRIGHTNESS_DEF;
964 sd->gain = GAIN_DEF;
965 sd->exposure = EXPOSURE_DEF;
Hans de Goede12ff9122008-07-17 10:30:56 -0300966 sd->freq = FREQ_DEF;
967 sd->contrast = CONTRAST_DEF;
968 sd->saturation = SATURATION_DEF;
969 sd->hue = HUE_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300970 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300971 reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300972 return 0;
973}
974
975/* this function is called at open time */
976static int sd_open(struct gspca_dev *gspca_dev)
977{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300978 reg_r(gspca_dev, 0x00);
979 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300980 return -ENODEV;
981 return 0;
982}
983
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300984static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300985{
986 int i;
987 const __u8 *data;
988 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
989
990 i = ARRAY_SIZE(pas106_data);
991 data = pas106_data[0];
992 while (--i >= 0) {
993 memcpy(&i2c1[2], data, 2);
994 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300995 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300996 PDEBUG(D_ERR, "i2c error pas106");
997 data += 2;
998 }
999}
1000
1001/* -- start the camera -- */
1002static void sd_start(struct gspca_dev *gspca_dev)
1003{
1004 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001005 int mode, l;
1006 const __u8 *sn9c10x;
1007 __u8 reg01, reg17;
1008 __u8 reg17_19[3];
1009
Jean-Francois Moinec2446b32008-07-05 11:49:20 -03001010 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001011 switch (sd->sensor) {
1012 case SENSOR_HV7131R:
1013 sn9c10x = initHv7131;
1014 reg17_19[0] = 0x60;
1015 reg17_19[1] = (mode << 4) | 0x8a;
1016 reg17_19[2] = 0x20;
1017 break;
1018 case SENSOR_OV6650:
1019 sn9c10x = initOv6650;
1020 reg17_19[0] = 0x68;
1021 reg17_19[1] = (mode << 4) | 0x8b;
1022 reg17_19[2] = 0x20;
1023 break;
1024 case SENSOR_OV7630:
1025 sn9c10x = initOv7630;
1026 reg17_19[0] = 0x68;
1027 reg17_19[1] = (mode << 4) | COMP2;
1028 reg17_19[2] = MCK_INIT1;
1029 break;
1030 case SENSOR_OV7630_3:
1031 sn9c10x = initOv7630_3;
1032 reg17_19[0] = 0x68;
1033 reg17_19[1] = (mode << 4) | COMP2;
1034 reg17_19[2] = MCK_INIT1;
1035 break;
1036 case SENSOR_PAS106:
1037 sn9c10x = initPas106;
1038 reg17_19[0] = 0x24; /* 0x28 */
1039 reg17_19[1] = (mode << 4) | COMP1;
1040 reg17_19[2] = MCK_INIT1;
1041 break;
1042 case SENSOR_PAS202:
1043 sn9c10x = initPas202;
1044 reg17_19[0] = mode ? 0x24 : 0x20;
1045 reg17_19[1] = (mode << 4) | 0x89;
1046 reg17_19[2] = 0x20;
1047 break;
1048 case SENSOR_TAS5110:
1049 sn9c10x = initTas5110;
1050 reg17_19[0] = 0x60;
1051 reg17_19[1] = (mode << 4) | 0x86;
1052 reg17_19[2] = 0x2b; /* 0xf3; */
1053 break;
1054 default:
1055/* case SENSOR_TAS5130CXX: */
1056 sn9c10x = initTas5130;
1057 reg17_19[0] = 0x60;
1058 reg17_19[1] = (mode << 4) | COMP;
1059 reg17_19[2] = mode ? 0x23 : 0x43;
1060 break;
1061 }
1062 switch (sd->sensor) {
1063 case SENSOR_OV7630:
1064 reg01 = 0x06;
1065 reg17 = 0x29;
Jean-Francois Moine1ff1e482008-07-17 09:37:57 -03001066 l = sizeof initOv7630;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001067 break;
1068 case SENSOR_OV7630_3:
1069 reg01 = 0x44;
1070 reg17 = 0x68;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -03001071 l = sizeof initOv7630_3;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001072 break;
1073 default:
1074 reg01 = sn9c10x[0];
1075 reg17 = sn9c10x[0x17 - 1];
1076 l = 0x1f;
1077 break;
1078 }
1079
1080 /* reg 0x01 bit 2 video transfert on */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001081 reg_w(gspca_dev, 0x01, &reg01, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001082 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001083 reg_w(gspca_dev, 0x17, &reg17, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001084/*fixme: for ov7630 102
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001085 reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001086 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001087 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001088 switch (sd->sensor) {
1089 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001090 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001091 sizeof hv7131_sensor_init);
1092 break;
1093 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001094 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001095 sizeof ov6650_sensor_init);
1096 break;
1097 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001098 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001099 sizeof ov7630_sensor_init_com);
1100 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001101 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001102 sizeof ov7630_sensor_init);
1103 break;
1104 case SENSOR_OV7630_3:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001105 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001106 sizeof ov7630_sensor_init_com);
1107 msleep(200);
Andoni Zubimendid87616f2008-07-17 05:35:52 -03001108 i2c_w(gspca_dev, ov7630_sensor_init_3[mode]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001109 break;
1110 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001111 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001112 break;
1113 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001114 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001115 sizeof pas202_sensor_init);
1116 break;
1117 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001118 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001119 sizeof tas5110_sensor_init);
1120 break;
1121 default:
1122/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001123 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001124 sizeof tas5130_sensor_init);
1125 break;
1126 }
Hans de Goede3647fea2008-07-15 05:36:30 -03001127 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
1128 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001129 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001130 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -03001131 /* H_start */
1132 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
1133 /* V_START */
1134 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001135 /* reset 0x17 SensorClk enable inv Clk 0x60 */
1136 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001137 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001138 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -03001139 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001140 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001141 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001142 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001143 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001144 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001145 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001146 msleep(20);
1147
Hans de Goededcef3232008-07-10 10:40:53 -03001148 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001149 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001150 setexposure(gspca_dev);
Hans de Goede66f35822008-07-16 10:16:28 -03001151 setfreq(gspca_dev);
Hans de Goede12ff9122008-07-17 10:30:56 -03001152 setsaturation(gspca_dev);
1153 sethue(gspca_dev);
1154 setcontrast(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001155
1156 sd->autogain_ignore_frames = 0;
1157 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001158}
1159
1160static void sd_stopN(struct gspca_dev *gspca_dev)
1161{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -03001162 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001163
1164 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001165 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001166}
1167
1168static void sd_stop0(struct gspca_dev *gspca_dev)
1169{
1170}
1171
1172static void sd_close(struct gspca_dev *gspca_dev)
1173{
1174}
1175
1176static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1177 struct gspca_frame *frame, /* target */
1178 unsigned char *data, /* isoc packet */
1179 int len) /* iso packet length */
1180{
Hans de Goede0d2a7222008-07-03 08:15:22 -03001181 int i;
Hans de Goededcef3232008-07-10 10:40:53 -03001182 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001183
Hans de Goedec36260ee2008-07-16 09:56:07 -03001184 /* frames start with:
1185 * ff ff 00 c4 c4 96 synchro
1186 * 00 (unknown)
1187 * xx (frame sequence / size / compression)
1188 * (xx) (idem - extra byte for sn9c103)
1189 * ll mm brightness sum inside auto exposure
1190 * ll mm brightness sum outside auto exposure
1191 * (xx xx xx xx xx) audio values for snc103
1192 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001193 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -03001194 for (i = 0; i < len - 6; i++) {
1195 if (data[0 + i] == 0xff
1196 && data[1 + i] == 0xff
1197 && data[2 + i] == 0x00
1198 && data[3 + i] == 0xc4
1199 && data[4 + i] == 0xc4
1200 && data[5 + i] == 0x96) { /* start of frame */
1201 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
1202 frame, data, 0);
Hans de Goedec36260ee2008-07-16 09:56:07 -03001203 if (len - i < sd->fr_h_sz) {
1204 atomic_set(&sd->avg_lum, -1);
1205 PDEBUG(D_STREAM, "packet too short to"
1206 " get avg brightness");
1207 } else if (sd->fr_h_sz == 12) {
1208 atomic_set(&sd->avg_lum,
1209 data[i + 8] +
Hans de Goededcef3232008-07-10 10:40:53 -03001210 (data[i + 9] << 8));
1211 } else {
Hans de Goedec36260ee2008-07-16 09:56:07 -03001212 atomic_set(&sd->avg_lum,
1213 data[i + 9] +
1214 (data[i + 10] << 8));
Hans de Goededcef3232008-07-10 10:40:53 -03001215 }
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -03001216 data += i + sd->fr_h_sz;
1217 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001218 gspca_frame_add(gspca_dev, FIRST_PACKET,
1219 frame, data, len);
1220 return;
1221 }
1222 }
1223 }
1224 gspca_frame_add(gspca_dev, INTER_PACKET,
1225 frame, data, len);
1226}
1227
1228static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1229{
1230 struct sd *sd = (struct sd *) gspca_dev;
1231
1232 sd->brightness = val;
1233 if (gspca_dev->streaming)
1234 setbrightness(gspca_dev);
1235 return 0;
1236}
1237
1238static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1239{
1240 struct sd *sd = (struct sd *) gspca_dev;
1241
1242 *val = sd->brightness;
1243 return 0;
1244}
1245
Hans de Goededcef3232008-07-10 10:40:53 -03001246static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001247{
1248 struct sd *sd = (struct sd *) gspca_dev;
1249
Hans de Goededcef3232008-07-10 10:40:53 -03001250 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001251 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001252 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001253 return 0;
1254}
1255
Hans de Goededcef3232008-07-10 10:40:53 -03001256static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001257{
1258 struct sd *sd = (struct sd *) gspca_dev;
1259
Hans de Goededcef3232008-07-10 10:40:53 -03001260 *val = sd->gain;
1261 return 0;
1262}
1263
1264static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1265{
1266 struct sd *sd = (struct sd *) gspca_dev;
1267
1268 sd->exposure = val;
1269 if (gspca_dev->streaming)
1270 setexposure(gspca_dev);
1271 return 0;
1272}
1273
1274static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1275{
1276 struct sd *sd = (struct sd *) gspca_dev;
1277
1278 *val = sd->exposure;
1279 return 0;
1280}
1281
1282static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1283{
1284 struct sd *sd = (struct sd *) gspca_dev;
1285
1286 sd->autogain = val;
1287 /* when switching to autogain set defaults to make sure
1288 we are on a valid point of the autogain gain /
1289 exposure knee graph, and give this change time to
1290 take effect before doing autogain. */
1291 if (sd->autogain) {
1292 sd->exposure = EXPOSURE_DEF;
1293 sd->gain = GAIN_DEF;
1294 if (gspca_dev->streaming) {
1295 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1296 setexposure(gspca_dev);
1297 setgain(gspca_dev);
1298 }
1299 }
1300
1301 return 0;
1302}
1303
1304static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1305{
1306 struct sd *sd = (struct sd *) gspca_dev;
1307
1308 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001309 return 0;
1310}
1311
Hans de Goede66f35822008-07-16 10:16:28 -03001312static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1313{
1314 struct sd *sd = (struct sd *) gspca_dev;
1315
1316 sd->freq = val;
1317 if (gspca_dev->streaming)
1318 setfreq(gspca_dev);
1319 return 0;
1320}
1321
1322static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1323{
1324 struct sd *sd = (struct sd *) gspca_dev;
1325
1326 *val = sd->freq;
1327 return 0;
1328}
1329
Hans de Goede12ff9122008-07-17 10:30:56 -03001330static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)
1331{
1332 struct sd *sd = (struct sd *) gspca_dev;
1333
1334 sd->saturation = val;
1335 if (gspca_dev->streaming)
1336 setsaturation(gspca_dev);
1337 return 0;
1338}
1339
1340static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)
1341{
1342 struct sd *sd = (struct sd *) gspca_dev;
1343
1344 *val = sd->saturation;
1345 return 0;
1346}
1347
1348static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
1349{
1350 struct sd *sd = (struct sd *) gspca_dev;
1351
1352 sd->hue = val;
1353 if (gspca_dev->streaming)
1354 sethue(gspca_dev);
1355 return 0;
1356}
1357
1358static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
1359{
1360 struct sd *sd = (struct sd *) gspca_dev;
1361
1362 *val = sd->hue;
1363 return 0;
1364}
1365
1366static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1367{
1368 struct sd *sd = (struct sd *) gspca_dev;
1369
1370 sd->contrast = val;
1371 if (gspca_dev->streaming)
1372 setcontrast(gspca_dev);
1373 return 0;
1374}
1375
1376static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1377{
1378 struct sd *sd = (struct sd *) gspca_dev;
1379
1380 *val = sd->contrast;
1381 return 0;
1382}
1383
Hans de Goede66f35822008-07-16 10:16:28 -03001384static int sd_querymenu(struct gspca_dev *gspca_dev,
1385 struct v4l2_querymenu *menu)
1386{
1387 switch (menu->id) {
1388 case V4L2_CID_POWER_LINE_FREQUENCY:
1389 switch (menu->index) {
1390 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1391 strcpy((char *) menu->name, "NoFliker");
1392 return 0;
1393 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1394 strcpy((char *) menu->name, "50 Hz");
1395 return 0;
1396 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1397 strcpy((char *) menu->name, "60 Hz");
1398 return 0;
1399 }
1400 break;
1401 }
1402 return -EINVAL;
1403}
1404
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001405/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001406static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001407 .name = MODULE_NAME,
1408 .ctrls = sd_ctrls,
1409 .nctrls = ARRAY_SIZE(sd_ctrls),
1410 .config = sd_config,
1411 .open = sd_open,
1412 .start = sd_start,
1413 .stopN = sd_stopN,
1414 .stop0 = sd_stop0,
1415 .close = sd_close,
1416 .pkt_scan = sd_pkt_scan,
Hans de Goede66f35822008-07-16 10:16:28 -03001417 .querymenu = sd_querymenu,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001418};
1419
1420/* -- module initialisation -- */
1421#define DVNM(name) .driver_info = (kernel_ulong_t) name
1422static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001423#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001424 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1425 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1426 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1427 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1428 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001429 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001430 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1431 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1432 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1433 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1434 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1435 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1436 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1437 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1438 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1439 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001440#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001441 {}
1442};
1443MODULE_DEVICE_TABLE(usb, device_table);
1444
1445/* -- device connect -- */
1446static int sd_probe(struct usb_interface *intf,
1447 const struct usb_device_id *id)
1448{
1449 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1450 THIS_MODULE);
1451}
1452
1453static struct usb_driver sd_driver = {
1454 .name = MODULE_NAME,
1455 .id_table = device_table,
1456 .probe = sd_probe,
1457 .disconnect = gspca_disconnect,
1458};
1459
1460/* -- module insert / remove -- */
1461static int __init sd_mod_init(void)
1462{
1463 if (usb_register(&sd_driver) < 0)
1464 return -1;
1465 PDEBUG(D_PROBE, "v%s registered", version);
1466 return 0;
1467}
1468static void __exit sd_mod_exit(void)
1469{
1470 usb_deregister(&sd_driver);
1471 PDEBUG(D_PROBE, "deregistered");
1472}
1473
1474module_init(sd_mod_init);
1475module_exit(sd_mod_exit);