blob: 4f9c9ecb06e850087e2be9c7d761ef64f4aaef8d [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 Goede6af492e2008-07-22 07:09:33 -030044 unsigned char frames_to_drop;
Hans de Goede66f35822008-07-16 10:16:28 -030045 unsigned char freq; /* light freq filter setting */
Hans de Goede12ff9122008-07-17 10:30:56 -030046 unsigned char saturation;
47 unsigned char hue;
48 unsigned char contrast;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030049
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -030050 unsigned char fr_h_sz; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030051 char sensor; /* Type of image sensor chip */
52#define SENSOR_HV7131R 0
53#define SENSOR_OV6650 1
54#define SENSOR_OV7630 2
Hans de Goede6af492e2008-07-22 07:09:33 -030055#define SENSOR_PAS106 3
56#define SENSOR_PAS202 4
57#define SENSOR_TAS5110 5
58#define SENSOR_TAS5130CXX 6
Hans de Goedea975a522008-07-16 15:29:11 -030059 char sensor_has_gain;
60 __u8 sensor_addr;
Hans de Goede6af492e2008-07-22 07:09:33 -030061 __u8 reg11;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030062};
63
64#define COMP2 0x8f
65#define COMP 0xc7 /* 0x87 //0x07 */
66#define COMP1 0xc9 /* 0x89 //0x09 */
67
68#define MCK_INIT 0x63
69#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
70
71#define SYS_CLK 0x04
72
Hans de Goededcef3232008-07-10 10:40:53 -030073/* We calculate the autogain at the end of the transfer of a frame, at this
74 moment a frame with the old settings is being transmitted, and a frame is
75 being captured with the old settings. So if we adjust the autogain we must
76 ignore atleast the 2 next frames for the new settings to come into effect
77 before doing any other adjustments */
78#define AUTOGAIN_IGNORE_FRAMES 3
Hans de Goedead5ef80d2008-07-14 10:11:42 -030079#define AUTOGAIN_DEADZONE 1000
Hans de Goededcef3232008-07-10 10:40:53 -030080#define DESIRED_AVG_LUM 7000
81
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030082/* V4L2 controls supported by the driver */
83static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
84static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goededcef3232008-07-10 10:40:53 -030085static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
86static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
87static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
88static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
89static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
90static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede66f35822008-07-16 10:16:28 -030091static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
92static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede12ff9122008-07-17 10:30:56 -030093static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val);
94static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);
95static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
96static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
97static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
98static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030099
100static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300101 {
102 {
103 .id = V4L2_CID_BRIGHTNESS,
104 .type = V4L2_CTRL_TYPE_INTEGER,
105 .name = "Brightness",
106 .minimum = 0,
107 .maximum = 255,
108 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -0300109#define BRIGHTNESS_DEF 127
110 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 },
112 .set = sd_setbrightness,
113 .get = sd_getbrightness,
114 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300115 {
116 {
Hans de Goededcef3232008-07-10 10:40:53 -0300117 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300118 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300119 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300120 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300121 .maximum = 255,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300122 .step = 1,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300123#define GAIN_DEF 127
124#define GAIN_KNEE 200
Hans de Goededcef3232008-07-10 10:40:53 -0300125 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300126 },
Hans de Goededcef3232008-07-10 10:40:53 -0300127 .set = sd_setgain,
128 .get = sd_getgain,
129 },
Hans de Goededcef3232008-07-10 10:40:53 -0300130 {
131 {
132 .id = V4L2_CID_EXPOSURE,
133 .type = V4L2_CTRL_TYPE_INTEGER,
134 .name = "Exposure",
Hans de Goedef4d52022008-07-15 09:36:42 -0300135#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
136#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
Hans de Goededcef3232008-07-10 10:40:53 -0300137 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300138 .maximum = 255,
Hans de Goededcef3232008-07-10 10:40:53 -0300139 .step = 1,
140 .default_value = EXPOSURE_DEF,
141 .flags = 0,
142 },
143 .set = sd_setexposure,
144 .get = sd_getexposure,
145 },
Hans de Goededcef3232008-07-10 10:40:53 -0300146 {
147 {
148 .id = V4L2_CID_AUTOGAIN,
149 .type = V4L2_CTRL_TYPE_BOOLEAN,
150 .name = "Automatic Gain (and Exposure)",
151 .minimum = 0,
152 .maximum = 1,
153 .step = 1,
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300154#define AUTOGAIN_DEF 1
155 .default_value = AUTOGAIN_DEF,
Hans de Goededcef3232008-07-10 10:40:53 -0300156 .flags = 0,
157 },
158 .set = sd_setautogain,
159 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300160 },
Hans de Goede66f35822008-07-16 10:16:28 -0300161 {
162 {
163 .id = V4L2_CID_POWER_LINE_FREQUENCY,
164 .type = V4L2_CTRL_TYPE_MENU,
165 .name = "Light frequency filter",
166 .minimum = 0,
167 .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
168 .step = 1,
169#define FREQ_DEF 1
170 .default_value = FREQ_DEF,
171 },
172 .set = sd_setfreq,
173 .get = sd_getfreq,
174 },
Hans de Goede12ff9122008-07-17 10:30:56 -0300175 {
176 {
177 .id = V4L2_CID_SATURATION,
178 .type = V4L2_CTRL_TYPE_INTEGER,
179 .name = "Saturation",
180 .minimum = 0,
181 .maximum = 255,
182 .step = 1,
183#define SATURATION_DEF 127
184 .default_value = SATURATION_DEF,
185 },
186 .set = sd_setsaturation,
187 .get = sd_getsaturation,
188 },
189 {
190 {
191 .id = V4L2_CID_HUE,
192 .type = V4L2_CTRL_TYPE_INTEGER,
193 .name = "Hue",
194 .minimum = 0,
195 .maximum = 255,
196 .step = 1,
197#define HUE_DEF 127
198 .default_value = HUE_DEF,
199 },
200 .set = sd_sethue,
201 .get = sd_gethue,
202 },
203 {
204 {
205 .id = V4L2_CID_CONTRAST,
206 .type = V4L2_CTRL_TYPE_INTEGER,
207 .name = "Contrast",
208 .minimum = 0,
209 .maximum = 255,
210 .step = 1,
211#define CONTRAST_DEF 127
212 .default_value = CONTRAST_DEF,
213 },
214 .set = sd_setcontrast,
215 .get = sd_getcontrast,
216 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300217};
218
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300219static struct v4l2_pix_format vga_mode[] = {
220 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
221 .bytesperline = 160,
222 .sizeimage = 160 * 120,
223 .colorspace = V4L2_COLORSPACE_SRGB,
224 .priv = 2},
225 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
226 .bytesperline = 320,
227 .sizeimage = 320 * 240,
228 .colorspace = V4L2_COLORSPACE_SRGB,
229 .priv = 1},
230 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
231 .bytesperline = 640,
232 .sizeimage = 640 * 480,
233 .colorspace = V4L2_COLORSPACE_SRGB,
234 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300235};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300236static struct v4l2_pix_format sif_mode[] = {
237 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
238 .bytesperline = 176,
239 .sizeimage = 176 * 144,
240 .colorspace = V4L2_COLORSPACE_SRGB,
241 .priv = 1},
242 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
243 .bytesperline = 352,
244 .sizeimage = 352 * 288,
245 .colorspace = V4L2_COLORSPACE_SRGB,
246 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300247};
248
249static const __u8 probe_ov7630[] = {0x08, 0x44};
250
251static const __u8 initHv7131[] = {
252 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
253 0x00, 0x00,
254 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
255 0x28, 0x1e, 0x60, 0x8a, 0x20,
256 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
257};
258static const __u8 hv7131_sensor_init[][8] = {
259 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
260 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
261 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
262 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
263 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
264};
265static const __u8 initOv6650[] = {
266 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
267 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
269 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
270};
271static const __u8 ov6650_sensor_init[][8] =
272{
273 /* Bright, contrast, etc are set througth SCBB interface.
274 * AVCAP on win2 do not send any data on this controls. */
275 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300276
277 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300278 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300279 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300280 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300281 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300282 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
283/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
284 * THIS SET GREEN SCREEN
285 * (pixels could be innverted in decode kind of "brg",
286 * but blue wont be there. Avoid this data ... */
287 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
288 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
289 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goede722103e2008-07-17 10:24:47 -0300290 /* Enable rgb brightness control */
291 {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
292 /* HDG: Note windows uses the line below, which sets both register 0x60
293 and 0x61 I believe these registers of the ov6650 are identical as
294 those of the ov7630, because if this is true the windows settings
295 add a bit additional red gain and a lot additional blue gain, which
296 matches my findings that the windows settings make blue much too
297 blue and red a little too red.
298 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
Hans de Goededcef3232008-07-10 10:40:53 -0300299 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300300 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
301 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300302};
Hans de Goededcef3232008-07-10 10:40:53 -0300303
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300304static const __u8 initOv7630[] = {
305 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
306 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
307 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
308 0x28, 0x1e, /* H & V sizes r15 .. r16 */
309 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
310 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
311};
312static const __u8 initOv7630_3[] = {
313 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
314 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300315 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300316 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300317 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
318 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
319 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
320 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300321};
Hans de Goede6af492e2008-07-22 07:09:33 -0300322static const __u8 ov7630_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300323 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
324 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
325/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300326 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300327 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
328 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
329 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
330 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
331 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
332 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
333 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
Andoni Zubimendi794af522008-07-16 08:33:14 -0300334 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
335/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300336 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
337 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
338 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
339 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
340 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
341 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
342};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300343
344static const __u8 initPas106[] = {
345 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
346 0x00, 0x00,
347 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
348 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
349 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
350};
351/* compression 0x86 mckinit1 0x2b */
352static const __u8 pas106_data[][2] = {
353 {0x02, 0x04}, /* Pixel Clock Divider 6 */
354 {0x03, 0x13}, /* Frame Time MSB */
355/* {0x03, 0x12}, * Frame Time MSB */
356 {0x04, 0x06}, /* Frame Time LSB */
357/* {0x04, 0x05}, * Frame Time LSB */
358 {0x05, 0x65}, /* Shutter Time Line Offset */
359/* {0x05, 0x6d}, * Shutter Time Line Offset */
360/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
361 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
362 {0x07, 0xc1}, /* Black Level Subtract Sign */
363/* {0x07, 0x00}, * Black Level Subtract Sign */
364 {0x08, 0x06}, /* Black Level Subtract Level */
365 {0x08, 0x06}, /* Black Level Subtract Level */
366/* {0x08, 0x01}, * Black Level Subtract Level */
367 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
368 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
369 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
370 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
371 {0x0d, 0x00}, /* Color GainH Pixel */
372 {0x0e, 0x0e}, /* Global Gain */
373 {0x0f, 0x00}, /* Contrast */
374 {0x10, 0x06}, /* H&V synchro polarity */
375 {0x11, 0x06}, /* ?default */
376 {0x12, 0x06}, /* DAC scale */
377 {0x14, 0x02}, /* ?default */
378 {0x13, 0x01}, /* Validate Settings */
379};
380static const __u8 initPas202[] = {
381 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
382 0x00, 0x00,
383 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
384 0x28, 0x1e, 0x28, 0x89, 0x30,
385 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
386};
387static const __u8 pas202_sensor_init[][8] = {
388 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
389 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
390 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
391 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
392 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
393 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
394 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
395 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
396 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
397 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
398 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
399 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
400
401 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
402 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
403 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
404 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
405 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
406 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
407 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
408 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
409};
410
411static const __u8 initTas5110[] = {
412 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
413 0x00, 0x00,
414 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
415 0x16, 0x12, 0x60, 0x86, 0x2b,
416 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
417};
418static const __u8 tas5110_sensor_init[][8] = {
419 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
420 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
421 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
422};
423
424static const __u8 initTas5130[] = {
425 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
426 0x00, 0x00,
427 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
428 0x28, 0x1e, 0x60, COMP, MCK_INIT,
429 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
430};
431static const __u8 tas5130_sensor_init[][8] = {
432/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
433 * shutter 0x47 short exposure? */
434 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
435 /* shutter 0x01 long exposure */
436 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
437};
438
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300439/* get one byte in gspca_dev->usb_buf */
440static void reg_r(struct gspca_dev *gspca_dev,
441 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300442{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300443 usb_control_msg(gspca_dev->dev,
444 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300445 0, /* request */
446 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
447 value,
448 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300449 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300450 500);
451}
452
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300453static void reg_w(struct gspca_dev *gspca_dev,
454 __u16 value,
455 const __u8 *buffer,
456 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300457{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300458#ifdef CONFIG_VIDEO_ADV_DEBUG
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300459 if (len > sizeof gspca_dev->usb_buf) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300460 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
461 return;
462 }
463#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300464 memcpy(gspca_dev->usb_buf, buffer, len);
465 usb_control_msg(gspca_dev->dev,
466 usb_sndctrlpipe(gspca_dev->dev, 0),
467 0x08, /* request */
468 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
469 value,
470 0, /* index */
471 gspca_dev->usb_buf, len,
472 500);
473}
474
475static void reg_w_big(struct gspca_dev *gspca_dev,
476 __u16 value,
477 const __u8 *buffer,
478 int len)
479{
480 __u8 *tmpbuf;
481
482 tmpbuf = kmalloc(len, GFP_KERNEL);
Hans de Goede0d2a7222008-07-03 08:15:22 -0300483 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300484 usb_control_msg(gspca_dev->dev,
485 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300486 0x08, /* request */
487 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
488 value,
489 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300490 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300491 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300492 kfree(tmpbuf);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300493}
494
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300495static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300496{
497 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300498
499 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300500 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300501 while (retry--) {
502 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300503 reg_r(gspca_dev, 0x08);
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300504 if (gspca_dev->usb_buf[0] & 0x04) {
505 if (gspca_dev->usb_buf[0] & 0x08)
506 return -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300507 return 0;
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300508 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300509 }
510 return -1;
511}
512
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300513static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300514 const __u8 buffer[][8], int len)
515{
516 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300517 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300518 len -= 8;
519 if (len <= 0)
520 break;
521 buffer++;
522 }
523}
524
525static void setbrightness(struct gspca_dev *gspca_dev)
526{
527 struct sd *sd = (struct sd *) gspca_dev;
528 __u8 value;
529
530 switch (sd->sensor) {
Hans de Goedea975a522008-07-16 15:29:11 -0300531 case SENSOR_OV6650:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532 case SENSOR_OV7630: {
533 __u8 i2cOV[] =
Hans de Goedea975a522008-07-16 15:29:11 -0300534 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300535
536 /* change reg 0x06 */
Hans de Goedea975a522008-07-16 15:29:11 -0300537 i2cOV[1] = sd->sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300538 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300539 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540 goto err;
541 break;
542 }
543 case SENSOR_PAS106: {
544 __u8 i2c1[] =
545 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
546
547 i2c1[3] = sd->brightness >> 3;
548 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300549 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300550 goto err;
551 i2c1[3] = 0x01;
552 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300553 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300554 goto err;
555 break;
556 }
557 case SENSOR_PAS202: {
558 /* __u8 i2cpexpo1[] =
559 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
560 __u8 i2cpexpo[] =
561 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
562 __u8 i2cp202[] =
563 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
564 static __u8 i2cpdoit[] =
565 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
566
567 /* change reg 0x10 */
568 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300569/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300570 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300571/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300572 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300573 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300574 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300575 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300576 goto err;
577 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300578 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300579 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300580 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300581 goto err;
582 break;
583 }
Hans de Goededcef3232008-07-10 10:40:53 -0300584 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300585 __u8 i2c[] =
586 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
587
588 value = 0xff - sd->brightness;
589 i2c[4] = value;
590 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300591 if (i2c_w(gspca_dev, i2c) < 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_TAS5110:
596 /* FIXME figure out howto control brightness on TAS5110 */
597 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300598 }
599 return;
600err:
601 PDEBUG(D_ERR, "i2c error brightness");
602}
Hans de Goededcef3232008-07-10 10:40:53 -0300603
604static void setsensorgain(struct gspca_dev *gspca_dev)
605{
606 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea975a522008-07-16 15:29:11 -0300607 unsigned char gain = sd->gain;
Hans de Goededcef3232008-07-10 10:40:53 -0300608
609 switch (sd->sensor) {
610
611 case SENSOR_TAS5110: {
612 __u8 i2c[] =
613 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
614
Hans de Goedea975a522008-07-16 15:29:11 -0300615 i2c[4] = 255 - gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300616 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300617 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300618 break;
619 }
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300620
Hans de Goedea975a522008-07-16 15:29:11 -0300621 case SENSOR_OV6650:
622 gain >>= 1;
623 /* fall thru */
Hans de Goede6af492e2008-07-22 07:09:33 -0300624 case SENSOR_OV7630: {
Hans de Goedea975a522008-07-16 15:29:11 -0300625 __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Andoni Zubimendi794af522008-07-16 08:33:14 -0300626
Hans de Goedea975a522008-07-16 15:29:11 -0300627 i2c[1] = sd->sensor_addr;
628 i2c[3] = gain >> 2;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300629 if (i2c_w(gspca_dev, i2c) < 0)
630 goto err;
631 break;
632 }
Hans de Goededcef3232008-07-10 10:40:53 -0300633 }
634 return;
635err:
636 PDEBUG(D_ERR, "i2c error gain");
637}
638
639static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300640{
641 struct sd *sd = (struct sd *) gspca_dev;
642 __u8 gain;
643 __u8 rgb_value;
644
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300645 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300646
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300647 /* red and blue gain */
648 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300649 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300650 /* green gain */
651 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300652 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300653
654 if (sd->sensor_has_gain)
655 setsensorgain(gspca_dev);
656}
657
658static void setexposure(struct gspca_dev *gspca_dev)
659{
660 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300661
662 switch (sd->sensor) {
663 case SENSOR_TAS5110: {
664 __u8 reg;
665
666 /* register 19's high nibble contains the sn9c10x clock divider
667 The high nibble configures the no fps according to the
668 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300669 reg = 120 * sd->exposure / 1000;
670 if (reg < 2)
671 reg = 2;
672 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300673 reg = 15;
674 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300675 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300676 break;
677 }
Hans de Goedea975a522008-07-16 15:29:11 -0300678 case SENSOR_OV6650:
Hans de Goede6af492e2008-07-22 07:09:33 -0300679 case SENSOR_OV7630: {
Hans de Goedea975a522008-07-16 15:29:11 -0300680 /* The ov6650 / ov7630 have 2 registers which both influence
681 exposure, register 11, whose low nibble sets the nr off fps
Hans de Goedef4d52022008-07-15 09:36:42 -0300682 according to: fps = 30 / (low_nibble + 1)
683
684 The fps configures the maximum exposure setting, but it is
685 possible to use less exposure then what the fps maximum
686 allows by setting register 10. register 10 configures the
687 actual exposure as quotient of the full exposure, with 0
688 being no exposure at all (not very usefull) and reg10_max
689 being max exposure possible at that framerate.
690
691 The code maps our 0 - 510 ms exposure ctrl to these 2
692 registers, trying to keep fps as high as possible.
693 */
Hans de Goede6af492e2008-07-22 07:09:33 -0300694 __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10};
695 int reg10, reg11, reg10_max;
696
Hans de Goede66f35822008-07-16 10:16:28 -0300697 /* ov6645 datasheet says reg10_max is 9a, but that uses
698 tline * 2 * reg10 as formula for calculating texpo, the
699 ov6650 probably uses the same formula as the 7730 which uses
700 tline * 4 * reg10, which explains why the reg10max we've
701 found experimentally for the ov6650 is exactly half that of
Hans de Goedea975a522008-07-16 15:29:11 -0300702 the ov6645. The ov7630 datasheet says the max is 0x41. */
Hans de Goede6af492e2008-07-22 07:09:33 -0300703 if (sd->sensor == SENSOR_OV6650) {
704 reg10_max = 0x4d;
705 i2c[4] = 0xc0; /* OV6650 needs non default vsync pol */
706 } else
707 reg10_max = 0x41;
Hans de Goedef4d52022008-07-15 09:36:42 -0300708
709 reg11 = (60 * sd->exposure + 999) / 1000;
710 if (reg11 < 1)
711 reg11 = 1;
712 else if (reg11 > 16)
713 reg11 = 16;
714
715 /* frame exposure time in ms = 1000 * reg11 / 30 ->
716 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
717 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
Hans de Goedea975a522008-07-16 15:29:11 -0300718
719 /* Don't allow this to get below 10 when using autogain, the
720 steps become very large (relatively) when below 10 causing
721 the image to oscilate from much too dark, to much too bright
722 and back again. */
723 if (sd->autogain && reg10 < 10)
724 reg10 = 10;
Hans de Goedef4d52022008-07-15 09:36:42 -0300725 else if (reg10 > reg10_max)
726 reg10 = reg10_max;
727
Hans de Goede6af492e2008-07-22 07:09:33 -0300728 /* In 640x480, if the reg11 has less than 3, the image is
729 unstable (not enough bandwidth). */
730 if (gspca_dev->width == 640 && reg11 < 3)
731 reg11 = 3;
732
Hans de Goedef4d52022008-07-15 09:36:42 -0300733 /* Write reg 10 and reg11 low nibble */
Hans de Goedea975a522008-07-16 15:29:11 -0300734 i2c[1] = sd->sensor_addr;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300735 i2c[3] = reg10;
736 i2c[4] |= reg11 - 1;
Hans de Goede6af492e2008-07-22 07:09:33 -0300737
738 /* If register 11 didn't change, don't change it */
739 if (sd->reg11 == reg11 )
740 i2c[0] = 0xa0;
741
742 if (i2c_w(gspca_dev, i2c) == 0)
743 sd->reg11 = reg11;
744 else
Andoni Zubimendi794af522008-07-16 08:33:14 -0300745 PDEBUG(D_ERR, "i2c error exposure");
746 break;
747 }
Hans de Goededcef3232008-07-10 10:40:53 -0300748 }
749}
750
Hans de Goede66f35822008-07-16 10:16:28 -0300751static void setfreq(struct gspca_dev *gspca_dev)
752{
753 struct sd *sd = (struct sd *) gspca_dev;
754
755 switch (sd->sensor) {
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300756 case SENSOR_OV6650:
Hans de Goede6af492e2008-07-22 07:09:33 -0300757 case SENSOR_OV7630: {
Hans de Goede66f35822008-07-16 10:16:28 -0300758 /* Framerate adjust register for artificial light 50 hz flicker
Hans de Goede6af492e2008-07-22 07:09:33 -0300759 compensation, for the ov6650 this is identical to ov6630
760 0x2b register, see ov6630 datasheet.
761 0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300762 __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goede66f35822008-07-16 10:16:28 -0300763 switch (sd->freq) {
764 default:
765/* case 0: * no filter*/
766/* case 2: * 60 hz */
767 i2c[3] = 0;
768 break;
769 case 1: /* 50 hz */
Hans de Goede722103e2008-07-17 10:24:47 -0300770 i2c[3] = (sd->sensor == SENSOR_OV6650)
771 ? 0x4f : 0x8a;
Hans de Goede66f35822008-07-16 10:16:28 -0300772 break;
773 }
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300774 i2c[1] = sd->sensor_addr;
Hans de Goede66f35822008-07-16 10:16:28 -0300775 if (i2c_w(gspca_dev, i2c) < 0)
776 PDEBUG(D_ERR, "i2c error setfreq");
777 break;
778 }
779 }
780}
781
Hans de Goede12ff9122008-07-17 10:30:56 -0300782static void setsaturation(struct gspca_dev *gspca_dev)
783{
784 struct sd *sd = (struct sd *) gspca_dev;
785
786 switch (sd->sensor) {
787/* case SENSOR_OV6650: */
Hans de Goede12ff9122008-07-17 10:30:56 -0300788 case SENSOR_OV7630: {
789 __u8 i2c[] = {0xa0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10};
790 i2c[1] = sd->sensor_addr;
791 i2c[3] = sd->saturation & 0xf0;
792 if (i2c_w(gspca_dev, i2c) < 0)
793 PDEBUG(D_ERR, "i2c error setsaturation");
794 else
795 PDEBUG(D_CONF, "saturation set to: %d",
796 (int)sd->saturation);
797 break;
798 }
799 }
800}
801
802static void sethue(struct gspca_dev *gspca_dev)
803{
804 struct sd *sd = (struct sd *) gspca_dev;
805
806 switch (sd->sensor) {
807/* case SENSOR_OV6650: */
Hans de Goede12ff9122008-07-17 10:30:56 -0300808 case SENSOR_OV7630: {
809 __u8 i2c[] = {0xa0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10};
810 i2c[1] = sd->sensor_addr;
811 i2c[3] = 0x20 | (sd->hue >> 3);
812 if (i2c_w(gspca_dev, i2c) < 0)
813 PDEBUG(D_ERR, "i2c error setsaturation");
814 else
815 PDEBUG(D_CONF, "hue set to: %d", (int)sd->hue);
816 break;
817 }
818 }
819}
820
821static void setcontrast(struct gspca_dev *gspca_dev)
822{
823 struct sd *sd = (struct sd *) gspca_dev;
824
825 switch (sd->sensor) {
826/* case SENSOR_OV6650: */
Hans de Goede12ff9122008-07-17 10:30:56 -0300827 case SENSOR_OV7630: {
828 __u8 i2c[] = {0xa0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10};
829 i2c[1] = sd->sensor_addr;
830 i2c[3] = 0x20 | (sd->contrast >> 3);
831 if (i2c_w(gspca_dev, i2c) < 0)
832 PDEBUG(D_ERR, "i2c error setcontrast");
833 else
834 PDEBUG(D_CONF, "contrast set to: %d",
835 (int)sd->contrast);
836 break;
837 }
838 }
839}
840
Hans de Goededcef3232008-07-10 10:40:53 -0300841
842static void do_autogain(struct gspca_dev *gspca_dev)
843{
844 struct sd *sd = (struct sd *) gspca_dev;
845 int avg_lum = atomic_read(&sd->avg_lum);
846
847 if (avg_lum == -1)
848 return;
849
850 if (sd->autogain_ignore_frames > 0)
851 sd->autogain_ignore_frames--;
852 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
853 sd->brightness * DESIRED_AVG_LUM / 127,
Hans de Goedea975a522008-07-16 15:29:11 -0300854 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
855 PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
856 (int)sd->gain, (int)sd->exposure);
Hans de Goededcef3232008-07-10 10:40:53 -0300857 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Hans de Goedea975a522008-07-16 15:29:11 -0300858 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300859}
860
861/* this function is called at probe time */
862static int sd_config(struct gspca_dev *gspca_dev,
863 const struct usb_device_id *id)
864{
865 struct sd *sd = (struct sd *) gspca_dev;
866 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300867 __u16 product;
868 int sif = 0;
869
Hans de Goededcef3232008-07-10 10:40:53 -0300870 /* nctrls depends upon the sensor, so we use a per cam copy */
871 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
872 gspca_dev->sd_desc = &sd->sd_desc;
873
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300874 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300875 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300876 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300877/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300878/* case 0x0c45: * Sonix */
879 switch (product) {
880 case 0x6001: /* SN9C102 */
881 case 0x6005: /* SN9C101 */
882 case 0x6007: /* SN9C101 */
883 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300884 sd->sensor_has_gain = 1;
885 sd->sd_desc.nctrls = 4;
886 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300887 sif = 1;
888 break;
889 case 0x6009: /* SN9C101 */
890 case 0x600d: /* SN9C101 */
891 case 0x6029: /* SN9C101 */
892 sd->sensor = SENSOR_PAS106;
893 sif = 1;
894 break;
895 case 0x6011: /* SN9C101 - SN9C101G */
896 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300897 sd->sensor_has_gain = 1;
Hans de Goedea975a522008-07-16 15:29:11 -0300898 sd->sensor_addr = 0x60;
Hans de Goede722103e2008-07-17 10:24:47 -0300899 sd->sd_desc.nctrls = 5;
Hans de Goededcef3232008-07-10 10:40:53 -0300900 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300901 sif = 1;
902 break;
903 case 0x6019: /* SN9C101 */
904 case 0x602c: /* SN9C102 */
905 case 0x602e: /* SN9C102 */
Hans de Goede6af492e2008-07-22 07:09:33 -0300906 case 0x60b0: /* SN9C103 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300907 sd->sensor = SENSOR_OV7630;
Hans de Goedea975a522008-07-16 15:29:11 -0300908 sd->sensor_addr = 0x21;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300909 sd->sensor_has_gain = 1;
Hans de Goede6af492e2008-07-22 07:09:33 -0300910 sd->sd_desc.nctrls = 5;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300911 sd->sd_desc.dq_callback = do_autogain;
Hans de Goede6af492e2008-07-22 07:09:33 -0300912 if (product == 0x60b0)
913 sd->fr_h_sz = 18; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300914 break;
915 case 0x6024: /* SN9C102 */
916 case 0x6025: /* SN9C102 */
917 sd->sensor = SENSOR_TAS5130CXX;
918 break;
919 case 0x6028: /* SN9C102 */
920 sd->sensor = SENSOR_PAS202;
921 break;
922 case 0x602d: /* SN9C102 */
923 sd->sensor = SENSOR_HV7131R;
924 break;
925 case 0x60af: /* SN9C103 */
926 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300927 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300928 break;
929 }
930/* break; */
931/* } */
932
933 cam = &gspca_dev->cam;
934 cam->dev_name = (char *) id->driver_info;
935 cam->epaddr = 0x01;
936 if (!sif) {
937 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300938 cam->nmodes = ARRAY_SIZE(vga_mode);
Hans de Goede6af492e2008-07-22 07:09:33 -0300939 if (product == 0x60b0) { /* SN9C103 with OV7630 */
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300940 /* We only have 320x240 & 640x480 */
941 cam->cam_mode++;
942 cam->nmodes--;
943 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300944 } else {
945 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300946 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300947 }
Hans de Goededcef3232008-07-10 10:40:53 -0300948 sd->brightness = BRIGHTNESS_DEF;
949 sd->gain = GAIN_DEF;
950 sd->exposure = EXPOSURE_DEF;
Hans de Goede6af492e2008-07-22 07:09:33 -0300951 sd->autogain = AUTOGAIN_DEF;
Hans de Goede12ff9122008-07-17 10:30:56 -0300952 sd->freq = FREQ_DEF;
953 sd->contrast = CONTRAST_DEF;
954 sd->saturation = SATURATION_DEF;
955 sd->hue = HUE_DEF;
Hans de Goede6af492e2008-07-22 07:09:33 -0300956
957 if (product == 0x60b0) /* SN9C103 with OV7630 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300958 reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
Hans de Goede6af492e2008-07-22 07:09:33 -0300959
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300960 return 0;
961}
962
963/* this function is called at open time */
964static int sd_open(struct gspca_dev *gspca_dev)
965{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300966 reg_r(gspca_dev, 0x00);
967 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300968 return -ENODEV;
969 return 0;
970}
971
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300972static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300973{
974 int i;
975 const __u8 *data;
976 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
977
978 i = ARRAY_SIZE(pas106_data);
979 data = pas106_data[0];
980 while (--i >= 0) {
981 memcpy(&i2c1[2], data, 2);
982 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300983 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300984 PDEBUG(D_ERR, "i2c error pas106");
985 data += 2;
986 }
987}
988
989/* -- start the camera -- */
990static void sd_start(struct gspca_dev *gspca_dev)
991{
992 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede6af492e2008-07-22 07:09:33 -0300993 int mode, l = 0x1f;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300994 const __u8 *sn9c10x;
995 __u8 reg01, reg17;
996 __u8 reg17_19[3];
997
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300998 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300999 switch (sd->sensor) {
1000 case SENSOR_HV7131R:
1001 sn9c10x = initHv7131;
1002 reg17_19[0] = 0x60;
1003 reg17_19[1] = (mode << 4) | 0x8a;
1004 reg17_19[2] = 0x20;
1005 break;
1006 case SENSOR_OV6650:
1007 sn9c10x = initOv6650;
1008 reg17_19[0] = 0x68;
1009 reg17_19[1] = (mode << 4) | 0x8b;
1010 reg17_19[2] = 0x20;
1011 break;
1012 case SENSOR_OV7630:
Hans de Goede6af492e2008-07-22 07:09:33 -03001013 if (sd->fr_h_sz == 18) { /* SN9C103 */
1014 sn9c10x = initOv7630_3;
1015 l = sizeof initOv7630_3;
1016 } else
1017 sn9c10x = initOv7630;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001018 reg17_19[0] = 0x68;
1019 reg17_19[1] = (mode << 4) | COMP2;
1020 reg17_19[2] = MCK_INIT1;
1021 break;
1022 case SENSOR_PAS106:
1023 sn9c10x = initPas106;
1024 reg17_19[0] = 0x24; /* 0x28 */
1025 reg17_19[1] = (mode << 4) | COMP1;
1026 reg17_19[2] = MCK_INIT1;
1027 break;
1028 case SENSOR_PAS202:
1029 sn9c10x = initPas202;
1030 reg17_19[0] = mode ? 0x24 : 0x20;
1031 reg17_19[1] = (mode << 4) | 0x89;
1032 reg17_19[2] = 0x20;
1033 break;
1034 case SENSOR_TAS5110:
1035 sn9c10x = initTas5110;
1036 reg17_19[0] = 0x60;
1037 reg17_19[1] = (mode << 4) | 0x86;
1038 reg17_19[2] = 0x2b; /* 0xf3; */
1039 break;
1040 default:
1041/* case SENSOR_TAS5130CXX: */
1042 sn9c10x = initTas5130;
1043 reg17_19[0] = 0x60;
1044 reg17_19[1] = (mode << 4) | COMP;
1045 reg17_19[2] = mode ? 0x23 : 0x43;
1046 break;
1047 }
Hans de Goede6af492e2008-07-22 07:09:33 -03001048
1049 /* Special case for SN9C101/2 with OV 7630 */
1050 /* HDG: is this really necessary we overwrite the values immediately
1051 afterwards with the ones from the template ?? */
1052 if (sd->sensor == SENSOR_OV7630 && sd->fr_h_sz == 12) {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001053 reg01 = 0x06;
1054 reg17 = 0x29;
Hans de Goede6af492e2008-07-22 07:09:33 -03001055 } else {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001056 reg01 = sn9c10x[0];
1057 reg17 = sn9c10x[0x17 - 1];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001058 }
1059
1060 /* reg 0x01 bit 2 video transfert on */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001061 reg_w(gspca_dev, 0x01, &reg01, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001062 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001063 reg_w(gspca_dev, 0x17, &reg17, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001064 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001065 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001066 switch (sd->sensor) {
1067 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001068 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001069 sizeof hv7131_sensor_init);
1070 break;
1071 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001072 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001073 sizeof ov6650_sensor_init);
1074 break;
1075 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001076 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001077 sizeof ov7630_sensor_init);
Hans de Goede6af492e2008-07-22 07:09:33 -03001078 if (sd->fr_h_sz == 18) { /* SN9C103 */
1079 const __u8 i2c[] = { 0xa0, 0x21, 0x13, 0x80, 0x00,
1080 0x00, 0x00, 0x10 };
1081 i2c_w(gspca_dev, i2c);
1082 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001083 break;
1084 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001085 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001086 break;
1087 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001088 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001089 sizeof pas202_sensor_init);
1090 break;
1091 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001092 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001093 sizeof tas5110_sensor_init);
1094 break;
1095 default:
1096/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001097 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001098 sizeof tas5130_sensor_init);
1099 break;
1100 }
Hans de Goede3647fea2008-07-15 05:36:30 -03001101 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
1102 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001103 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001104 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -03001105 /* H_start */
1106 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
1107 /* V_START */
1108 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001109 /* reset 0x17 SensorClk enable inv Clk 0x60 */
1110 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001111 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001112 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -03001113 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001114 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001115 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001116 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001117 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001118 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001119 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001120 msleep(20);
1121
Hans de Goede6af492e2008-07-22 07:09:33 -03001122 sd->reg11 = -1;
1123
Hans de Goededcef3232008-07-10 10:40:53 -03001124 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001125 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001126 setexposure(gspca_dev);
Hans de Goede66f35822008-07-16 10:16:28 -03001127 setfreq(gspca_dev);
Hans de Goede12ff9122008-07-17 10:30:56 -03001128 setsaturation(gspca_dev);
1129 sethue(gspca_dev);
1130 setcontrast(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001131
Hans de Goede6af492e2008-07-22 07:09:33 -03001132 sd->frames_to_drop = 0;
Hans de Goededcef3232008-07-10 10:40:53 -03001133 sd->autogain_ignore_frames = 0;
1134 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001135}
1136
1137static void sd_stopN(struct gspca_dev *gspca_dev)
1138{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -03001139 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001140
1141 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001142 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001143}
1144
1145static void sd_stop0(struct gspca_dev *gspca_dev)
1146{
1147}
1148
1149static void sd_close(struct gspca_dev *gspca_dev)
1150{
1151}
1152
1153static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1154 struct gspca_frame *frame, /* target */
1155 unsigned char *data, /* isoc packet */
1156 int len) /* iso packet length */
1157{
Hans de Goede0d2a7222008-07-03 08:15:22 -03001158 int i;
Hans de Goededcef3232008-07-10 10:40:53 -03001159 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001160
Hans de Goedec36260ee2008-07-16 09:56:07 -03001161 /* frames start with:
1162 * ff ff 00 c4 c4 96 synchro
1163 * 00 (unknown)
1164 * xx (frame sequence / size / compression)
1165 * (xx) (idem - extra byte for sn9c103)
1166 * ll mm brightness sum inside auto exposure
1167 * ll mm brightness sum outside auto exposure
1168 * (xx xx xx xx xx) audio values for snc103
1169 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001170 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -03001171 for (i = 0; i < len - 6; i++) {
1172 if (data[0 + i] == 0xff
1173 && data[1 + i] == 0xff
1174 && data[2 + i] == 0x00
1175 && data[3 + i] == 0xc4
1176 && data[4 + i] == 0xc4
1177 && data[5 + i] == 0x96) { /* start of frame */
Hans de Goede6af492e2008-07-22 07:09:33 -03001178 int lum = -1;
1179 int pkt_type = LAST_PACKET;
1180
Hans de Goedec36260ee2008-07-16 09:56:07 -03001181 if (len - i < sd->fr_h_sz) {
Hans de Goedec36260ee2008-07-16 09:56:07 -03001182 PDEBUG(D_STREAM, "packet too short to"
1183 " get avg brightness");
1184 } else if (sd->fr_h_sz == 12) {
Hans de Goede6af492e2008-07-22 07:09:33 -03001185 lum = data[i + 8] + (data[i + 9] << 8);
Hans de Goededcef3232008-07-10 10:40:53 -03001186 } else {
Hans de Goede6af492e2008-07-22 07:09:33 -03001187 lum = data[i + 9] +
1188 (data[i + 10] << 8);
Hans de Goededcef3232008-07-10 10:40:53 -03001189 }
Hans de Goede6af492e2008-07-22 07:09:33 -03001190 if (lum == 0) {
1191 lum = -1;
1192 sd->frames_to_drop = 2;
1193 }
1194 atomic_set(&sd->avg_lum, lum);
1195
1196 if (sd->frames_to_drop) {
1197 sd->frames_to_drop--;
1198 pkt_type = DISCARD_PACKET;
1199 }
1200
1201 frame = gspca_frame_add(gspca_dev, pkt_type,
1202 frame, data, 0);
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -03001203 data += i + sd->fr_h_sz;
1204 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001205 gspca_frame_add(gspca_dev, FIRST_PACKET,
1206 frame, data, len);
1207 return;
1208 }
1209 }
1210 }
1211 gspca_frame_add(gspca_dev, INTER_PACKET,
1212 frame, data, len);
1213}
1214
1215static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1216{
1217 struct sd *sd = (struct sd *) gspca_dev;
1218
1219 sd->brightness = val;
1220 if (gspca_dev->streaming)
1221 setbrightness(gspca_dev);
1222 return 0;
1223}
1224
1225static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1226{
1227 struct sd *sd = (struct sd *) gspca_dev;
1228
1229 *val = sd->brightness;
1230 return 0;
1231}
1232
Hans de Goededcef3232008-07-10 10:40:53 -03001233static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001234{
1235 struct sd *sd = (struct sd *) gspca_dev;
1236
Hans de Goededcef3232008-07-10 10:40:53 -03001237 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001238 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001239 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001240 return 0;
1241}
1242
Hans de Goededcef3232008-07-10 10:40:53 -03001243static int sd_getgain(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 *val = sd->gain;
1248 return 0;
1249}
1250
1251static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1252{
1253 struct sd *sd = (struct sd *) gspca_dev;
1254
1255 sd->exposure = val;
1256 if (gspca_dev->streaming)
1257 setexposure(gspca_dev);
1258 return 0;
1259}
1260
1261static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1262{
1263 struct sd *sd = (struct sd *) gspca_dev;
1264
1265 *val = sd->exposure;
1266 return 0;
1267}
1268
1269static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1270{
1271 struct sd *sd = (struct sd *) gspca_dev;
1272
1273 sd->autogain = val;
1274 /* when switching to autogain set defaults to make sure
1275 we are on a valid point of the autogain gain /
1276 exposure knee graph, and give this change time to
1277 take effect before doing autogain. */
1278 if (sd->autogain) {
1279 sd->exposure = EXPOSURE_DEF;
1280 sd->gain = GAIN_DEF;
1281 if (gspca_dev->streaming) {
1282 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1283 setexposure(gspca_dev);
1284 setgain(gspca_dev);
1285 }
1286 }
1287
1288 return 0;
1289}
1290
1291static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1292{
1293 struct sd *sd = (struct sd *) gspca_dev;
1294
1295 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001296 return 0;
1297}
1298
Hans de Goede66f35822008-07-16 10:16:28 -03001299static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1300{
1301 struct sd *sd = (struct sd *) gspca_dev;
1302
1303 sd->freq = val;
1304 if (gspca_dev->streaming)
1305 setfreq(gspca_dev);
1306 return 0;
1307}
1308
1309static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1310{
1311 struct sd *sd = (struct sd *) gspca_dev;
1312
1313 *val = sd->freq;
1314 return 0;
1315}
1316
Hans de Goede12ff9122008-07-17 10:30:56 -03001317static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)
1318{
1319 struct sd *sd = (struct sd *) gspca_dev;
1320
1321 sd->saturation = val;
1322 if (gspca_dev->streaming)
1323 setsaturation(gspca_dev);
1324 return 0;
1325}
1326
1327static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)
1328{
1329 struct sd *sd = (struct sd *) gspca_dev;
1330
1331 *val = sd->saturation;
1332 return 0;
1333}
1334
1335static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
1336{
1337 struct sd *sd = (struct sd *) gspca_dev;
1338
1339 sd->hue = val;
1340 if (gspca_dev->streaming)
1341 sethue(gspca_dev);
1342 return 0;
1343}
1344
1345static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
1346{
1347 struct sd *sd = (struct sd *) gspca_dev;
1348
1349 *val = sd->hue;
1350 return 0;
1351}
1352
1353static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1354{
1355 struct sd *sd = (struct sd *) gspca_dev;
1356
1357 sd->contrast = val;
1358 if (gspca_dev->streaming)
1359 setcontrast(gspca_dev);
1360 return 0;
1361}
1362
1363static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1364{
1365 struct sd *sd = (struct sd *) gspca_dev;
1366
1367 *val = sd->contrast;
1368 return 0;
1369}
1370
Hans de Goede66f35822008-07-16 10:16:28 -03001371static int sd_querymenu(struct gspca_dev *gspca_dev,
1372 struct v4l2_querymenu *menu)
1373{
1374 switch (menu->id) {
1375 case V4L2_CID_POWER_LINE_FREQUENCY:
1376 switch (menu->index) {
1377 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1378 strcpy((char *) menu->name, "NoFliker");
1379 return 0;
1380 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1381 strcpy((char *) menu->name, "50 Hz");
1382 return 0;
1383 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1384 strcpy((char *) menu->name, "60 Hz");
1385 return 0;
1386 }
1387 break;
1388 }
1389 return -EINVAL;
1390}
1391
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001392/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001393static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001394 .name = MODULE_NAME,
1395 .ctrls = sd_ctrls,
1396 .nctrls = ARRAY_SIZE(sd_ctrls),
1397 .config = sd_config,
1398 .open = sd_open,
1399 .start = sd_start,
1400 .stopN = sd_stopN,
1401 .stop0 = sd_stop0,
1402 .close = sd_close,
1403 .pkt_scan = sd_pkt_scan,
Hans de Goede66f35822008-07-16 10:16:28 -03001404 .querymenu = sd_querymenu,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001405};
1406
1407/* -- module initialisation -- */
1408#define DVNM(name) .driver_info = (kernel_ulong_t) name
1409static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001410#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001411 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1412 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1413 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1414 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1415 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Hans de Goede5de39b22008-07-17 10:34:28 -03001416#endif
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001417 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Hans de Goede5de39b22008-07-17 10:34:28 -03001418#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001419 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1420 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1421 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1422 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1423 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1424 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1425 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1426 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1427 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1428 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001429#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001430 {}
1431};
1432MODULE_DEVICE_TABLE(usb, device_table);
1433
1434/* -- device connect -- */
1435static int sd_probe(struct usb_interface *intf,
1436 const struct usb_device_id *id)
1437{
1438 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1439 THIS_MODULE);
1440}
1441
1442static struct usb_driver sd_driver = {
1443 .name = MODULE_NAME,
1444 .id_table = device_table,
1445 .probe = sd_probe,
1446 .disconnect = gspca_disconnect,
1447};
1448
1449/* -- module insert / remove -- */
1450static int __init sd_mod_init(void)
1451{
1452 if (usb_register(&sd_driver) < 0)
1453 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001454 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001455 return 0;
1456}
1457static void __exit sd_mod_exit(void)
1458{
1459 usb_deregister(&sd_driver);
1460 PDEBUG(D_PROBE, "deregistered");
1461}
1462
1463module_init(sd_mod_init);
1464module_exit(sd_mod_exit);