blob: d34d582e5f598f5b4a0354eedb19a6e786d7f220 [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 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030048
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -030049 unsigned char fr_h_sz; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030050 char sensor; /* Type of image sensor chip */
51#define SENSOR_HV7131R 0
52#define SENSOR_OV6650 1
53#define SENSOR_OV7630 2
54#define SENSOR_OV7630_3 3
55#define SENSOR_PAS106 4
56#define SENSOR_PAS202 5
57#define SENSOR_TAS5110 6
58#define SENSOR_TAS5130CXX 7
Hans de Goedea975a522008-07-16 15:29:11 -030059 char sensor_has_gain;
60 __u8 sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030061};
62
63#define COMP2 0x8f
64#define COMP 0xc7 /* 0x87 //0x07 */
65#define COMP1 0xc9 /* 0x89 //0x09 */
66
67#define MCK_INIT 0x63
68#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
69
70#define SYS_CLK 0x04
71
Hans de Goededcef3232008-07-10 10:40:53 -030072/* We calculate the autogain at the end of the transfer of a frame, at this
73 moment a frame with the old settings is being transmitted, and a frame is
74 being captured with the old settings. So if we adjust the autogain we must
75 ignore atleast the 2 next frames for the new settings to come into effect
76 before doing any other adjustments */
77#define AUTOGAIN_IGNORE_FRAMES 3
Hans de Goedead5ef80d2008-07-14 10:11:42 -030078#define AUTOGAIN_DEADZONE 1000
Hans de Goededcef3232008-07-10 10:40:53 -030079#define DESIRED_AVG_LUM 7000
80
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030081/* V4L2 controls supported by the driver */
82static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
83static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goededcef3232008-07-10 10:40:53 -030084static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
86static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
88static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
89static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede66f35822008-07-16 10:16:28 -030090static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
91static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030092
93static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030094 {
95 {
96 .id = V4L2_CID_BRIGHTNESS,
97 .type = V4L2_CTRL_TYPE_INTEGER,
98 .name = "Brightness",
99 .minimum = 0,
100 .maximum = 255,
101 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -0300102#define BRIGHTNESS_DEF 127
103 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104 },
105 .set = sd_setbrightness,
106 .get = sd_getbrightness,
107 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300108 {
109 {
Hans de Goededcef3232008-07-10 10:40:53 -0300110 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300112 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300113 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300114 .maximum = 255,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300115 .step = 1,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300116#define GAIN_DEF 127
117#define GAIN_KNEE 200
Hans de Goededcef3232008-07-10 10:40:53 -0300118 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300119 },
Hans de Goededcef3232008-07-10 10:40:53 -0300120 .set = sd_setgain,
121 .get = sd_getgain,
122 },
Hans de Goededcef3232008-07-10 10:40:53 -0300123 {
124 {
125 .id = V4L2_CID_EXPOSURE,
126 .type = V4L2_CTRL_TYPE_INTEGER,
127 .name = "Exposure",
Hans de Goedef4d52022008-07-15 09:36:42 -0300128#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
129#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
Hans de Goededcef3232008-07-10 10:40:53 -0300130 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300131 .maximum = 255,
Hans de Goededcef3232008-07-10 10:40:53 -0300132 .step = 1,
133 .default_value = EXPOSURE_DEF,
134 .flags = 0,
135 },
136 .set = sd_setexposure,
137 .get = sd_getexposure,
138 },
Hans de Goededcef3232008-07-10 10:40:53 -0300139 {
140 {
141 .id = V4L2_CID_AUTOGAIN,
142 .type = V4L2_CTRL_TYPE_BOOLEAN,
143 .name = "Automatic Gain (and Exposure)",
144 .minimum = 0,
145 .maximum = 1,
146 .step = 1,
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300147#define AUTOGAIN_DEF 1
148 .default_value = AUTOGAIN_DEF,
Hans de Goededcef3232008-07-10 10:40:53 -0300149 .flags = 0,
150 },
151 .set = sd_setautogain,
152 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300153 },
Hans de Goede66f35822008-07-16 10:16:28 -0300154 {
155 {
156 .id = V4L2_CID_POWER_LINE_FREQUENCY,
157 .type = V4L2_CTRL_TYPE_MENU,
158 .name = "Light frequency filter",
159 .minimum = 0,
160 .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
161 .step = 1,
162#define FREQ_DEF 1
163 .default_value = FREQ_DEF,
164 },
165 .set = sd_setfreq,
166 .get = sd_getfreq,
167 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300168};
169
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300170static struct v4l2_pix_format vga_mode[] = {
171 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
172 .bytesperline = 160,
173 .sizeimage = 160 * 120,
174 .colorspace = V4L2_COLORSPACE_SRGB,
175 .priv = 2},
176 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
177 .bytesperline = 320,
178 .sizeimage = 320 * 240,
179 .colorspace = V4L2_COLORSPACE_SRGB,
180 .priv = 1},
181 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
182 .bytesperline = 640,
183 .sizeimage = 640 * 480,
184 .colorspace = V4L2_COLORSPACE_SRGB,
185 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300186};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300187static struct v4l2_pix_format sif_mode[] = {
188 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
189 .bytesperline = 176,
190 .sizeimage = 176 * 144,
191 .colorspace = V4L2_COLORSPACE_SRGB,
192 .priv = 1},
193 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
194 .bytesperline = 352,
195 .sizeimage = 352 * 288,
196 .colorspace = V4L2_COLORSPACE_SRGB,
197 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300198};
199
200static const __u8 probe_ov7630[] = {0x08, 0x44};
201
202static const __u8 initHv7131[] = {
203 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
204 0x00, 0x00,
205 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
206 0x28, 0x1e, 0x60, 0x8a, 0x20,
207 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
208};
209static const __u8 hv7131_sensor_init[][8] = {
210 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
211 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
212 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
213 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
214 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
215};
216static const __u8 initOv6650[] = {
217 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
218 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
220 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
221};
222static const __u8 ov6650_sensor_init[][8] =
223{
224 /* Bright, contrast, etc are set througth SCBB interface.
225 * AVCAP on win2 do not send any data on this controls. */
226 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300227
228 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300229 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300230 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300231 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300232 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300233 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
234/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
235 * THIS SET GREEN SCREEN
236 * (pixels could be innverted in decode kind of "brg",
237 * but blue wont be there. Avoid this data ... */
238 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
239 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
240 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goede722103e2008-07-17 10:24:47 -0300241 /* Enable rgb brightness control */
242 {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
243 /* HDG: Note windows uses the line below, which sets both register 0x60
244 and 0x61 I believe these registers of the ov6650 are identical as
245 those of the ov7630, because if this is true the windows settings
246 add a bit additional red gain and a lot additional blue gain, which
247 matches my findings that the windows settings make blue much too
248 blue and red a little too red.
249 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
Hans de Goededcef3232008-07-10 10:40:53 -0300250 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300251 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
252 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300253};
Hans de Goededcef3232008-07-10 10:40:53 -0300254
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300255static const __u8 initOv7630[] = {
256 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
257 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
258 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
259 0x28, 0x1e, /* H & V sizes r15 .. r16 */
260 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
261 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
262};
263static const __u8 initOv7630_3[] = {
264 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
265 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300266 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300267 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300268 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
269 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
270 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
271 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300272};
273static const __u8 ov7630_sensor_init_com[][8] = {
274 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
275 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
276/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300277 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300278 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
279 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
280 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
281 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
282 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
283 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
284 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
Andoni Zubimendi794af522008-07-16 08:33:14 -0300285 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
286/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300287 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
288 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
289 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
290 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
291 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
292 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
293};
294static const __u8 ov7630_sensor_init[][8] = {
295 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
296 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
297 {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
298 {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
299 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
300};
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300301static const __u8 ov7630_sensor_init_3[][8] = {
302 {0xa0, 0x21, 0x2a, 0xa0, 0x00, 0x00, 0x00, 0x10},
303 {0xa0, 0x21, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x10},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300304};
305
306static const __u8 initPas106[] = {
307 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
308 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
310 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
311 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
312};
313/* compression 0x86 mckinit1 0x2b */
314static const __u8 pas106_data[][2] = {
315 {0x02, 0x04}, /* Pixel Clock Divider 6 */
316 {0x03, 0x13}, /* Frame Time MSB */
317/* {0x03, 0x12}, * Frame Time MSB */
318 {0x04, 0x06}, /* Frame Time LSB */
319/* {0x04, 0x05}, * Frame Time LSB */
320 {0x05, 0x65}, /* Shutter Time Line Offset */
321/* {0x05, 0x6d}, * Shutter Time Line Offset */
322/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
323 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
324 {0x07, 0xc1}, /* Black Level Subtract Sign */
325/* {0x07, 0x00}, * Black Level Subtract Sign */
326 {0x08, 0x06}, /* Black Level Subtract Level */
327 {0x08, 0x06}, /* Black Level Subtract Level */
328/* {0x08, 0x01}, * Black Level Subtract Level */
329 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
330 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
331 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
332 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
333 {0x0d, 0x00}, /* Color GainH Pixel */
334 {0x0e, 0x0e}, /* Global Gain */
335 {0x0f, 0x00}, /* Contrast */
336 {0x10, 0x06}, /* H&V synchro polarity */
337 {0x11, 0x06}, /* ?default */
338 {0x12, 0x06}, /* DAC scale */
339 {0x14, 0x02}, /* ?default */
340 {0x13, 0x01}, /* Validate Settings */
341};
342static const __u8 initPas202[] = {
343 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
344 0x00, 0x00,
345 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
346 0x28, 0x1e, 0x28, 0x89, 0x30,
347 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
348};
349static const __u8 pas202_sensor_init[][8] = {
350 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
351 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
352 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
353 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
354 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
355 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
356 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
357 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
358 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
359 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
360 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
361 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
362
363 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
364 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
365 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
366 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
367 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
368 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
369 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
370 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
371};
372
373static const __u8 initTas5110[] = {
374 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
375 0x00, 0x00,
376 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
377 0x16, 0x12, 0x60, 0x86, 0x2b,
378 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
379};
380static const __u8 tas5110_sensor_init[][8] = {
381 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
382 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
383 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
384};
385
386static const __u8 initTas5130[] = {
387 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
388 0x00, 0x00,
389 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
390 0x28, 0x1e, 0x60, COMP, MCK_INIT,
391 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
392};
393static const __u8 tas5130_sensor_init[][8] = {
394/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
395 * shutter 0x47 short exposure? */
396 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
397 /* shutter 0x01 long exposure */
398 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
399};
400
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300401/* get one byte in gspca_dev->usb_buf */
402static void reg_r(struct gspca_dev *gspca_dev,
403 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300404{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300405 usb_control_msg(gspca_dev->dev,
406 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300407 0, /* request */
408 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
409 value,
410 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300411 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300412 500);
413}
414
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300415static void reg_w(struct gspca_dev *gspca_dev,
416 __u16 value,
417 const __u8 *buffer,
418 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300419{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300420#ifdef CONFIG_VIDEO_ADV_DEBUG
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300421 if (len > sizeof gspca_dev->usb_buf) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300422 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
423 return;
424 }
425#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300426 memcpy(gspca_dev->usb_buf, buffer, len);
427 usb_control_msg(gspca_dev->dev,
428 usb_sndctrlpipe(gspca_dev->dev, 0),
429 0x08, /* request */
430 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
431 value,
432 0, /* index */
433 gspca_dev->usb_buf, len,
434 500);
435}
436
437static void reg_w_big(struct gspca_dev *gspca_dev,
438 __u16 value,
439 const __u8 *buffer,
440 int len)
441{
442 __u8 *tmpbuf;
443
444 tmpbuf = kmalloc(len, GFP_KERNEL);
Hans de Goede0d2a7222008-07-03 08:15:22 -0300445 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300446 usb_control_msg(gspca_dev->dev,
447 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300448 0x08, /* request */
449 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
450 value,
451 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300452 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300453 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300454 kfree(tmpbuf);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300455}
456
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300457static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300458{
459 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300460
461 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300462 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300463 while (retry--) {
464 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300465 reg_r(gspca_dev, 0x08);
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300466 if (gspca_dev->usb_buf[0] & 0x04) {
467 if (gspca_dev->usb_buf[0] & 0x08)
468 return -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300469 return 0;
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300470 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300471 }
472 return -1;
473}
474
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300475static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300476 const __u8 buffer[][8], int len)
477{
478 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300479 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300480 len -= 8;
481 if (len <= 0)
482 break;
483 buffer++;
484 }
485}
486
487static void setbrightness(struct gspca_dev *gspca_dev)
488{
489 struct sd *sd = (struct sd *) gspca_dev;
490 __u8 value;
491
492 switch (sd->sensor) {
Hans de Goedea975a522008-07-16 15:29:11 -0300493 case SENSOR_OV6650:
Andoni Zubimendi794af522008-07-16 08:33:14 -0300494 case SENSOR_OV7630_3:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300495 case SENSOR_OV7630: {
496 __u8 i2cOV[] =
Hans de Goedea975a522008-07-16 15:29:11 -0300497 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300498
499 /* change reg 0x06 */
Hans de Goedea975a522008-07-16 15:29:11 -0300500 i2cOV[1] = sd->sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300501 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300502 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503 goto err;
504 break;
505 }
506 case SENSOR_PAS106: {
507 __u8 i2c1[] =
508 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
509
510 i2c1[3] = sd->brightness >> 3;
511 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300512 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300513 goto err;
514 i2c1[3] = 0x01;
515 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300516 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517 goto err;
518 break;
519 }
520 case SENSOR_PAS202: {
521 /* __u8 i2cpexpo1[] =
522 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
523 __u8 i2cpexpo[] =
524 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
525 __u8 i2cp202[] =
526 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
527 static __u8 i2cpdoit[] =
528 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
529
530 /* change reg 0x10 */
531 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300532/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300533 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300534/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300535 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300536 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300537 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300538 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300539 goto err;
540 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300541 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300542 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300543 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300544 goto err;
545 break;
546 }
Hans de Goededcef3232008-07-10 10:40:53 -0300547 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300548 __u8 i2c[] =
549 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
550
551 value = 0xff - sd->brightness;
552 i2c[4] = value;
553 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300554 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300555 goto err;
556 break;
557 }
Hans de Goededcef3232008-07-10 10:40:53 -0300558 case SENSOR_TAS5110:
559 /* FIXME figure out howto control brightness on TAS5110 */
560 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300561 }
562 return;
563err:
564 PDEBUG(D_ERR, "i2c error brightness");
565}
Hans de Goededcef3232008-07-10 10:40:53 -0300566
567static void setsensorgain(struct gspca_dev *gspca_dev)
568{
569 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea975a522008-07-16 15:29:11 -0300570 unsigned char gain = sd->gain;
Hans de Goededcef3232008-07-10 10:40:53 -0300571
572 switch (sd->sensor) {
573
574 case SENSOR_TAS5110: {
575 __u8 i2c[] =
576 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
577
Hans de Goedea975a522008-07-16 15:29:11 -0300578 i2c[4] = 255 - gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300579 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300580 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300581 break;
582 }
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300583
Hans de Goedea975a522008-07-16 15:29:11 -0300584 case SENSOR_OV6650:
585 gain >>= 1;
586 /* fall thru */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300587 case SENSOR_OV7630_3: {
Hans de Goedea975a522008-07-16 15:29:11 -0300588 __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Andoni Zubimendi794af522008-07-16 08:33:14 -0300589
Hans de Goedea975a522008-07-16 15:29:11 -0300590 i2c[1] = sd->sensor_addr;
591 i2c[3] = gain >> 2;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300592 if (i2c_w(gspca_dev, i2c) < 0)
593 goto err;
594 break;
595 }
Hans de Goededcef3232008-07-10 10:40:53 -0300596 }
597 return;
598err:
599 PDEBUG(D_ERR, "i2c error gain");
600}
601
602static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300603{
604 struct sd *sd = (struct sd *) gspca_dev;
605 __u8 gain;
606 __u8 rgb_value;
607
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300608 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300609
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300610 /* red and blue gain */
611 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300612 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300613 /* green gain */
614 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300615 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300616
617 if (sd->sensor_has_gain)
618 setsensorgain(gspca_dev);
619}
620
621static void setexposure(struct gspca_dev *gspca_dev)
622{
623 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300624
625 switch (sd->sensor) {
626 case SENSOR_TAS5110: {
627 __u8 reg;
628
629 /* register 19's high nibble contains the sn9c10x clock divider
630 The high nibble configures the no fps according to the
631 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300632 reg = 120 * sd->exposure / 1000;
633 if (reg < 2)
634 reg = 2;
635 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300636 reg = 15;
637 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300638 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300639 break;
640 }
Hans de Goedea975a522008-07-16 15:29:11 -0300641 case SENSOR_OV6650:
642 case SENSOR_OV7630_3: {
643 /* The ov6650 / ov7630 have 2 registers which both influence
644 exposure, register 11, whose low nibble sets the nr off fps
Hans de Goedef4d52022008-07-15 09:36:42 -0300645 according to: fps = 30 / (low_nibble + 1)
646
647 The fps configures the maximum exposure setting, but it is
648 possible to use less exposure then what the fps maximum
649 allows by setting register 10. register 10 configures the
650 actual exposure as quotient of the full exposure, with 0
651 being no exposure at all (not very usefull) and reg10_max
652 being max exposure possible at that framerate.
653
654 The code maps our 0 - 510 ms exposure ctrl to these 2
655 registers, trying to keep fps as high as possible.
656 */
Hans de Goedea975a522008-07-16 15:29:11 -0300657 __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
Hans de Goedef4d52022008-07-15 09:36:42 -0300658 int reg10, reg11;
Hans de Goede66f35822008-07-16 10:16:28 -0300659 /* ov6645 datasheet says reg10_max is 9a, but that uses
660 tline * 2 * reg10 as formula for calculating texpo, the
661 ov6650 probably uses the same formula as the 7730 which uses
662 tline * 4 * reg10, which explains why the reg10max we've
663 found experimentally for the ov6650 is exactly half that of
Hans de Goedea975a522008-07-16 15:29:11 -0300664 the ov6645. The ov7630 datasheet says the max is 0x41. */
Hans de Goede722103e2008-07-17 10:24:47 -0300665 const int reg10_max = (sd->sensor == SENSOR_OV6650)
666 ? 0x4d : 0x41;
Hans de Goedef4d52022008-07-15 09:36:42 -0300667
668 reg11 = (60 * sd->exposure + 999) / 1000;
669 if (reg11 < 1)
670 reg11 = 1;
671 else if (reg11 > 16)
672 reg11 = 16;
673
674 /* frame exposure time in ms = 1000 * reg11 / 30 ->
675 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
676 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
Hans de Goedea975a522008-07-16 15:29:11 -0300677
678 /* Don't allow this to get below 10 when using autogain, the
679 steps become very large (relatively) when below 10 causing
680 the image to oscilate from much too dark, to much too bright
681 and back again. */
682 if (sd->autogain && reg10 < 10)
683 reg10 = 10;
Hans de Goedef4d52022008-07-15 09:36:42 -0300684 else if (reg10 > reg10_max)
685 reg10 = reg10_max;
686
687 /* Write reg 10 and reg11 low nibble */
Hans de Goedea975a522008-07-16 15:29:11 -0300688 i2c[1] = sd->sensor_addr;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300689 i2c[3] = reg10;
690 i2c[4] |= reg11 - 1;
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300691 if (sd->sensor == SENSOR_OV7630_3) {
692 __u8 reg76 = reg10 & 0x03;
693 __u8 i2c_reg76[] = {0xa0, 0x21, 0x76, 0x00,
694 0x00, 0x00, 0x00, 0x10};
695 reg10 >>= 2;
696 i2c_reg76[3] = reg76;
697 if (i2c_w(gspca_dev, i2c_reg76) < 0)
698 PDEBUG(D_ERR, "i2c error exposure");
699 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300700 if (i2c_w(gspca_dev, i2c) < 0)
701 PDEBUG(D_ERR, "i2c error exposure");
702 break;
703 }
Hans de Goededcef3232008-07-10 10:40:53 -0300704 }
705}
706
Hans de Goede66f35822008-07-16 10:16:28 -0300707static void setfreq(struct gspca_dev *gspca_dev)
708{
709 struct sd *sd = (struct sd *) gspca_dev;
710
711 switch (sd->sensor) {
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300712 case SENSOR_OV6650:
713 case SENSOR_OV7630_3: {
Hans de Goede66f35822008-07-16 10:16:28 -0300714 /* Framerate adjust register for artificial light 50 hz flicker
715 compensation, identical to ov6630 0x2b register, see ov6630
716 datasheet.
717 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300718 __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goede66f35822008-07-16 10:16:28 -0300719 switch (sd->freq) {
720 default:
721/* case 0: * no filter*/
722/* case 2: * 60 hz */
723 i2c[3] = 0;
724 break;
725 case 1: /* 50 hz */
Hans de Goede722103e2008-07-17 10:24:47 -0300726 i2c[3] = (sd->sensor == SENSOR_OV6650)
727 ? 0x4f : 0x8a;
Hans de Goede66f35822008-07-16 10:16:28 -0300728 break;
729 }
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300730 i2c[1] = sd->sensor_addr;
Hans de Goede66f35822008-07-16 10:16:28 -0300731 if (i2c_w(gspca_dev, i2c) < 0)
732 PDEBUG(D_ERR, "i2c error setfreq");
733 break;
734 }
735 }
736}
737
Hans de Goededcef3232008-07-10 10:40:53 -0300738
739static void do_autogain(struct gspca_dev *gspca_dev)
740{
741 struct sd *sd = (struct sd *) gspca_dev;
742 int avg_lum = atomic_read(&sd->avg_lum);
743
744 if (avg_lum == -1)
745 return;
746
747 if (sd->autogain_ignore_frames > 0)
748 sd->autogain_ignore_frames--;
749 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
750 sd->brightness * DESIRED_AVG_LUM / 127,
Hans de Goedea975a522008-07-16 15:29:11 -0300751 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
752 PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
753 (int)sd->gain, (int)sd->exposure);
Hans de Goededcef3232008-07-10 10:40:53 -0300754 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Hans de Goedea975a522008-07-16 15:29:11 -0300755 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300756}
757
758/* this function is called at probe time */
759static int sd_config(struct gspca_dev *gspca_dev,
760 const struct usb_device_id *id)
761{
762 struct sd *sd = (struct sd *) gspca_dev;
763 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300764 __u16 product;
765 int sif = 0;
766
Hans de Goededcef3232008-07-10 10:40:53 -0300767 /* nctrls depends upon the sensor, so we use a per cam copy */
768 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
769 gspca_dev->sd_desc = &sd->sd_desc;
770
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300771 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300772 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300773 sd->autogain = AUTOGAIN_DEF; /* default is autogain active */
Hans de Goede66f35822008-07-16 10:16:28 -0300774 sd->freq = FREQ_DEF;
Hans de Goededcef3232008-07-10 10:40:53 -0300775
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300776 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300777/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300778/* case 0x0c45: * Sonix */
779 switch (product) {
780 case 0x6001: /* SN9C102 */
781 case 0x6005: /* SN9C101 */
782 case 0x6007: /* SN9C101 */
783 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300784 sd->sensor_has_gain = 1;
785 sd->sd_desc.nctrls = 4;
786 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300787 sif = 1;
788 break;
789 case 0x6009: /* SN9C101 */
790 case 0x600d: /* SN9C101 */
791 case 0x6029: /* SN9C101 */
792 sd->sensor = SENSOR_PAS106;
793 sif = 1;
794 break;
795 case 0x6011: /* SN9C101 - SN9C101G */
796 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300797 sd->sensor_has_gain = 1;
Hans de Goedea975a522008-07-16 15:29:11 -0300798 sd->sensor_addr = 0x60;
Hans de Goede722103e2008-07-17 10:24:47 -0300799 sd->sd_desc.nctrls = 5;
Hans de Goededcef3232008-07-10 10:40:53 -0300800 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300801 sif = 1;
802 break;
803 case 0x6019: /* SN9C101 */
804 case 0x602c: /* SN9C102 */
805 case 0x602e: /* SN9C102 */
806 sd->sensor = SENSOR_OV7630;
Hans de Goedea975a522008-07-16 15:29:11 -0300807 sd->sensor_addr = 0x21;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300808 break;
809 case 0x60b0: /* SN9C103 */
810 sd->sensor = SENSOR_OV7630_3;
Hans de Goedea975a522008-07-16 15:29:11 -0300811 sd->sensor_addr = 0x21;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300812 sd->fr_h_sz = 18; /* size of frame header */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300813 sd->sensor_has_gain = 1;
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300814 sd->sd_desc.nctrls = 5;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300815 sd->sd_desc.dq_callback = do_autogain;
816 sd->autogain = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300817 break;
818 case 0x6024: /* SN9C102 */
819 case 0x6025: /* SN9C102 */
820 sd->sensor = SENSOR_TAS5130CXX;
821 break;
822 case 0x6028: /* SN9C102 */
823 sd->sensor = SENSOR_PAS202;
824 break;
825 case 0x602d: /* SN9C102 */
826 sd->sensor = SENSOR_HV7131R;
827 break;
828 case 0x60af: /* SN9C103 */
829 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300830 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300831 break;
832 }
833/* break; */
834/* } */
835
836 cam = &gspca_dev->cam;
837 cam->dev_name = (char *) id->driver_info;
838 cam->epaddr = 0x01;
839 if (!sif) {
840 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300841 cam->nmodes = ARRAY_SIZE(vga_mode);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300842 if (sd->sensor == SENSOR_OV7630_3) {
843 /* We only have 320x240 & 640x480 */
844 cam->cam_mode++;
845 cam->nmodes--;
846 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300847 } else {
848 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300849 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300850 }
Hans de Goededcef3232008-07-10 10:40:53 -0300851 sd->brightness = BRIGHTNESS_DEF;
852 sd->gain = GAIN_DEF;
853 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300854 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300855 reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300856 return 0;
857}
858
859/* this function is called at open time */
860static int sd_open(struct gspca_dev *gspca_dev)
861{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300862 reg_r(gspca_dev, 0x00);
863 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300864 return -ENODEV;
865 return 0;
866}
867
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300868static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300869{
870 int i;
871 const __u8 *data;
872 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
873
874 i = ARRAY_SIZE(pas106_data);
875 data = pas106_data[0];
876 while (--i >= 0) {
877 memcpy(&i2c1[2], data, 2);
878 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300879 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300880 PDEBUG(D_ERR, "i2c error pas106");
881 data += 2;
882 }
883}
884
885/* -- start the camera -- */
886static void sd_start(struct gspca_dev *gspca_dev)
887{
888 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300889 int mode, l;
890 const __u8 *sn9c10x;
891 __u8 reg01, reg17;
892 __u8 reg17_19[3];
893
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300894 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300895 switch (sd->sensor) {
896 case SENSOR_HV7131R:
897 sn9c10x = initHv7131;
898 reg17_19[0] = 0x60;
899 reg17_19[1] = (mode << 4) | 0x8a;
900 reg17_19[2] = 0x20;
901 break;
902 case SENSOR_OV6650:
903 sn9c10x = initOv6650;
904 reg17_19[0] = 0x68;
905 reg17_19[1] = (mode << 4) | 0x8b;
906 reg17_19[2] = 0x20;
907 break;
908 case SENSOR_OV7630:
909 sn9c10x = initOv7630;
910 reg17_19[0] = 0x68;
911 reg17_19[1] = (mode << 4) | COMP2;
912 reg17_19[2] = MCK_INIT1;
913 break;
914 case SENSOR_OV7630_3:
915 sn9c10x = initOv7630_3;
916 reg17_19[0] = 0x68;
917 reg17_19[1] = (mode << 4) | COMP2;
918 reg17_19[2] = MCK_INIT1;
919 break;
920 case SENSOR_PAS106:
921 sn9c10x = initPas106;
922 reg17_19[0] = 0x24; /* 0x28 */
923 reg17_19[1] = (mode << 4) | COMP1;
924 reg17_19[2] = MCK_INIT1;
925 break;
926 case SENSOR_PAS202:
927 sn9c10x = initPas202;
928 reg17_19[0] = mode ? 0x24 : 0x20;
929 reg17_19[1] = (mode << 4) | 0x89;
930 reg17_19[2] = 0x20;
931 break;
932 case SENSOR_TAS5110:
933 sn9c10x = initTas5110;
934 reg17_19[0] = 0x60;
935 reg17_19[1] = (mode << 4) | 0x86;
936 reg17_19[2] = 0x2b; /* 0xf3; */
937 break;
938 default:
939/* case SENSOR_TAS5130CXX: */
940 sn9c10x = initTas5130;
941 reg17_19[0] = 0x60;
942 reg17_19[1] = (mode << 4) | COMP;
943 reg17_19[2] = mode ? 0x23 : 0x43;
944 break;
945 }
946 switch (sd->sensor) {
947 case SENSOR_OV7630:
948 reg01 = 0x06;
949 reg17 = 0x29;
Jean-Francois Moine1ff1e482008-07-17 09:37:57 -0300950 l = sizeof initOv7630;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300951 break;
952 case SENSOR_OV7630_3:
953 reg01 = 0x44;
954 reg17 = 0x68;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300955 l = sizeof initOv7630_3;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300956 break;
957 default:
958 reg01 = sn9c10x[0];
959 reg17 = sn9c10x[0x17 - 1];
960 l = 0x1f;
961 break;
962 }
963
964 /* reg 0x01 bit 2 video transfert on */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300965 reg_w(gspca_dev, 0x01, &reg01, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300966 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300967 reg_w(gspca_dev, 0x17, &reg17, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300968/*fixme: for ov7630 102
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300969 reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300970 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300971 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300972 switch (sd->sensor) {
973 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300974 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300975 sizeof hv7131_sensor_init);
976 break;
977 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300978 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300979 sizeof ov6650_sensor_init);
980 break;
981 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300982 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300983 sizeof ov7630_sensor_init_com);
984 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300985 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300986 sizeof ov7630_sensor_init);
987 break;
988 case SENSOR_OV7630_3:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300989 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300990 sizeof ov7630_sensor_init_com);
991 msleep(200);
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300992 i2c_w(gspca_dev, ov7630_sensor_init_3[mode]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300993 break;
994 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300995 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300996 break;
997 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300998 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300999 sizeof pas202_sensor_init);
1000 break;
1001 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001002 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001003 sizeof tas5110_sensor_init);
1004 break;
1005 default:
1006/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001007 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001008 sizeof tas5130_sensor_init);
1009 break;
1010 }
Hans de Goede3647fea2008-07-15 05:36:30 -03001011 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
1012 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001013 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001014 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -03001015 /* H_start */
1016 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
1017 /* V_START */
1018 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001019 /* reset 0x17 SensorClk enable inv Clk 0x60 */
1020 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001021 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001022 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -03001023 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001024 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001025 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001026 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001027 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001028 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001029 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001030 msleep(20);
1031
Hans de Goededcef3232008-07-10 10:40:53 -03001032 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001033 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001034 setexposure(gspca_dev);
Hans de Goede66f35822008-07-16 10:16:28 -03001035 setfreq(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001036
1037 sd->autogain_ignore_frames = 0;
1038 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001039}
1040
1041static void sd_stopN(struct gspca_dev *gspca_dev)
1042{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -03001043 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001044
1045 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001046 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001047}
1048
1049static void sd_stop0(struct gspca_dev *gspca_dev)
1050{
1051}
1052
1053static void sd_close(struct gspca_dev *gspca_dev)
1054{
1055}
1056
1057static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1058 struct gspca_frame *frame, /* target */
1059 unsigned char *data, /* isoc packet */
1060 int len) /* iso packet length */
1061{
Hans de Goede0d2a7222008-07-03 08:15:22 -03001062 int i;
Hans de Goededcef3232008-07-10 10:40:53 -03001063 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001064
Hans de Goedec36260ee2008-07-16 09:56:07 -03001065 /* frames start with:
1066 * ff ff 00 c4 c4 96 synchro
1067 * 00 (unknown)
1068 * xx (frame sequence / size / compression)
1069 * (xx) (idem - extra byte for sn9c103)
1070 * ll mm brightness sum inside auto exposure
1071 * ll mm brightness sum outside auto exposure
1072 * (xx xx xx xx xx) audio values for snc103
1073 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001074 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -03001075 for (i = 0; i < len - 6; i++) {
1076 if (data[0 + i] == 0xff
1077 && data[1 + i] == 0xff
1078 && data[2 + i] == 0x00
1079 && data[3 + i] == 0xc4
1080 && data[4 + i] == 0xc4
1081 && data[5 + i] == 0x96) { /* start of frame */
1082 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
1083 frame, data, 0);
Hans de Goedec36260ee2008-07-16 09:56:07 -03001084 if (len - i < sd->fr_h_sz) {
1085 atomic_set(&sd->avg_lum, -1);
1086 PDEBUG(D_STREAM, "packet too short to"
1087 " get avg brightness");
1088 } else if (sd->fr_h_sz == 12) {
1089 atomic_set(&sd->avg_lum,
1090 data[i + 8] +
Hans de Goededcef3232008-07-10 10:40:53 -03001091 (data[i + 9] << 8));
1092 } else {
Hans de Goedec36260ee2008-07-16 09:56:07 -03001093 atomic_set(&sd->avg_lum,
1094 data[i + 9] +
1095 (data[i + 10] << 8));
Hans de Goededcef3232008-07-10 10:40:53 -03001096 }
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -03001097 data += i + sd->fr_h_sz;
1098 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001099 gspca_frame_add(gspca_dev, FIRST_PACKET,
1100 frame, data, len);
1101 return;
1102 }
1103 }
1104 }
1105 gspca_frame_add(gspca_dev, INTER_PACKET,
1106 frame, data, len);
1107}
1108
1109static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1110{
1111 struct sd *sd = (struct sd *) gspca_dev;
1112
1113 sd->brightness = val;
1114 if (gspca_dev->streaming)
1115 setbrightness(gspca_dev);
1116 return 0;
1117}
1118
1119static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1120{
1121 struct sd *sd = (struct sd *) gspca_dev;
1122
1123 *val = sd->brightness;
1124 return 0;
1125}
1126
Hans de Goededcef3232008-07-10 10:40:53 -03001127static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001128{
1129 struct sd *sd = (struct sd *) gspca_dev;
1130
Hans de Goededcef3232008-07-10 10:40:53 -03001131 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001132 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001133 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001134 return 0;
1135}
1136
Hans de Goededcef3232008-07-10 10:40:53 -03001137static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001138{
1139 struct sd *sd = (struct sd *) gspca_dev;
1140
Hans de Goededcef3232008-07-10 10:40:53 -03001141 *val = sd->gain;
1142 return 0;
1143}
1144
1145static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1146{
1147 struct sd *sd = (struct sd *) gspca_dev;
1148
1149 sd->exposure = val;
1150 if (gspca_dev->streaming)
1151 setexposure(gspca_dev);
1152 return 0;
1153}
1154
1155static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1156{
1157 struct sd *sd = (struct sd *) gspca_dev;
1158
1159 *val = sd->exposure;
1160 return 0;
1161}
1162
1163static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1164{
1165 struct sd *sd = (struct sd *) gspca_dev;
1166
1167 sd->autogain = val;
1168 /* when switching to autogain set defaults to make sure
1169 we are on a valid point of the autogain gain /
1170 exposure knee graph, and give this change time to
1171 take effect before doing autogain. */
1172 if (sd->autogain) {
1173 sd->exposure = EXPOSURE_DEF;
1174 sd->gain = GAIN_DEF;
1175 if (gspca_dev->streaming) {
1176 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1177 setexposure(gspca_dev);
1178 setgain(gspca_dev);
1179 }
1180 }
1181
1182 return 0;
1183}
1184
1185static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1186{
1187 struct sd *sd = (struct sd *) gspca_dev;
1188
1189 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001190 return 0;
1191}
1192
Hans de Goede66f35822008-07-16 10:16:28 -03001193static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1194{
1195 struct sd *sd = (struct sd *) gspca_dev;
1196
1197 sd->freq = val;
1198 if (gspca_dev->streaming)
1199 setfreq(gspca_dev);
1200 return 0;
1201}
1202
1203static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1204{
1205 struct sd *sd = (struct sd *) gspca_dev;
1206
1207 *val = sd->freq;
1208 return 0;
1209}
1210
1211static int sd_querymenu(struct gspca_dev *gspca_dev,
1212 struct v4l2_querymenu *menu)
1213{
1214 switch (menu->id) {
1215 case V4L2_CID_POWER_LINE_FREQUENCY:
1216 switch (menu->index) {
1217 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1218 strcpy((char *) menu->name, "NoFliker");
1219 return 0;
1220 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1221 strcpy((char *) menu->name, "50 Hz");
1222 return 0;
1223 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1224 strcpy((char *) menu->name, "60 Hz");
1225 return 0;
1226 }
1227 break;
1228 }
1229 return -EINVAL;
1230}
1231
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001232/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001233static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001234 .name = MODULE_NAME,
1235 .ctrls = sd_ctrls,
1236 .nctrls = ARRAY_SIZE(sd_ctrls),
1237 .config = sd_config,
1238 .open = sd_open,
1239 .start = sd_start,
1240 .stopN = sd_stopN,
1241 .stop0 = sd_stop0,
1242 .close = sd_close,
1243 .pkt_scan = sd_pkt_scan,
Hans de Goede66f35822008-07-16 10:16:28 -03001244 .querymenu = sd_querymenu,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001245};
1246
1247/* -- module initialisation -- */
1248#define DVNM(name) .driver_info = (kernel_ulong_t) name
1249static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001250#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001251 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1252 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1253 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1254 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1255 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001256 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001257 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1258 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1259 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1260 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1261 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1262 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1263 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1264 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1265 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1266 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001267#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001268 {}
1269};
1270MODULE_DEVICE_TABLE(usb, device_table);
1271
1272/* -- device connect -- */
1273static int sd_probe(struct usb_interface *intf,
1274 const struct usb_device_id *id)
1275{
1276 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1277 THIS_MODULE);
1278}
1279
1280static struct usb_driver sd_driver = {
1281 .name = MODULE_NAME,
1282 .id_table = device_table,
1283 .probe = sd_probe,
1284 .disconnect = gspca_disconnect,
1285};
1286
1287/* -- module insert / remove -- */
1288static int __init sd_mod_init(void)
1289{
1290 if (usb_register(&sd_driver) < 0)
1291 return -1;
1292 PDEBUG(D_PROBE, "v%s registered", version);
1293 return 0;
1294}
1295static void __exit sd_mod_exit(void)
1296{
1297 usb_deregister(&sd_driver);
1298 PDEBUG(D_PROBE, "deregistered");
1299}
1300
1301module_init(sd_mod_init);
1302module_exit(sd_mod_exit);