blob: 045ed6b7d053f54fea63d0c6be93b735f21414cc [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * sonix sn9c102 (bayer) library
3 * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
4 * Add Pas106 Stefano Mozzi (C) 2004
5 *
6 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#define MODULE_NAME "sonixb"
24
25#include "gspca.h"
26
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -030027#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
28static const char version[] = "2.1.7";
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030029
30MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
31MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
32MODULE_LICENSE("GPL");
33
34/* specific webcam descriptor */
35struct sd {
36 struct gspca_dev gspca_dev; /* !! must be the first item */
37
Hans de Goededcef3232008-07-10 10:40:53 -030038 struct sd_desc sd_desc; /* our nctrls differ dependend upon the
39 sensor, so we use a per cam copy */
40 atomic_t avg_lum;
41
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 Goededcef3232008-07-10 10:40:53 -0300241 /* Disable autobright ? */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300242 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300243 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300244 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
245 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300246};
Hans de Goededcef3232008-07-10 10:40:53 -0300247
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300248static const __u8 initOv7630[] = {
249 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
250 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
251 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
252 0x28, 0x1e, /* H & V sizes r15 .. r16 */
253 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
254 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
255};
256static const __u8 initOv7630_3[] = {
257 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
258 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300259 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300260 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300261 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
262 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
263 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
264 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300265};
266static const __u8 ov7630_sensor_init_com[][8] = {
267 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
268 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
269/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300270 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300271 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
272 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
273 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
274 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
275 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
276 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
277 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
Andoni Zubimendi794af522008-07-16 08:33:14 -0300278 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
279/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300280 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
281 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
282 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
283 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
284 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
285 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
286};
287static const __u8 ov7630_sensor_init[][8] = {
288 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
289 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
290 {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
291 {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
292 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
293};
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300294static const __u8 ov7630_sensor_init_3[][8] = {
295 {0xa0, 0x21, 0x2a, 0xa0, 0x00, 0x00, 0x00, 0x10},
296 {0xa0, 0x21, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x10},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300297};
298
299static const __u8 initPas106[] = {
300 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
301 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
303 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
304 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
305};
306/* compression 0x86 mckinit1 0x2b */
307static const __u8 pas106_data[][2] = {
308 {0x02, 0x04}, /* Pixel Clock Divider 6 */
309 {0x03, 0x13}, /* Frame Time MSB */
310/* {0x03, 0x12}, * Frame Time MSB */
311 {0x04, 0x06}, /* Frame Time LSB */
312/* {0x04, 0x05}, * Frame Time LSB */
313 {0x05, 0x65}, /* Shutter Time Line Offset */
314/* {0x05, 0x6d}, * Shutter Time Line Offset */
315/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
316 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
317 {0x07, 0xc1}, /* Black Level Subtract Sign */
318/* {0x07, 0x00}, * Black Level Subtract Sign */
319 {0x08, 0x06}, /* Black Level Subtract Level */
320 {0x08, 0x06}, /* Black Level Subtract Level */
321/* {0x08, 0x01}, * Black Level Subtract Level */
322 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
323 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
324 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
325 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
326 {0x0d, 0x00}, /* Color GainH Pixel */
327 {0x0e, 0x0e}, /* Global Gain */
328 {0x0f, 0x00}, /* Contrast */
329 {0x10, 0x06}, /* H&V synchro polarity */
330 {0x11, 0x06}, /* ?default */
331 {0x12, 0x06}, /* DAC scale */
332 {0x14, 0x02}, /* ?default */
333 {0x13, 0x01}, /* Validate Settings */
334};
335static const __u8 initPas202[] = {
336 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
337 0x00, 0x00,
338 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
339 0x28, 0x1e, 0x28, 0x89, 0x30,
340 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
341};
342static const __u8 pas202_sensor_init[][8] = {
343 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
344 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
345 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
346 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
347 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
348 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
349 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
350 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
351 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
352 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
353 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
354 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
355
356 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
357 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
358 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
359 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
360 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
361 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
362 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
363 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
364};
365
366static const __u8 initTas5110[] = {
367 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
368 0x00, 0x00,
369 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
370 0x16, 0x12, 0x60, 0x86, 0x2b,
371 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
372};
373static const __u8 tas5110_sensor_init[][8] = {
374 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
375 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
376 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
377};
378
379static const __u8 initTas5130[] = {
380 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
381 0x00, 0x00,
382 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
383 0x28, 0x1e, 0x60, COMP, MCK_INIT,
384 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
385};
386static const __u8 tas5130_sensor_init[][8] = {
387/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
388 * shutter 0x47 short exposure? */
389 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
390 /* shutter 0x01 long exposure */
391 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
392};
393
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300394/* get one byte in gspca_dev->usb_buf */
395static void reg_r(struct gspca_dev *gspca_dev,
396 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300397{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300398 usb_control_msg(gspca_dev->dev,
399 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300400 0, /* request */
401 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
402 value,
403 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300404 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405 500);
406}
407
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300408static void reg_w(struct gspca_dev *gspca_dev,
409 __u16 value,
410 const __u8 *buffer,
411 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300412{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300413#ifdef CONFIG_VIDEO_ADV_DEBUG
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300414 if (len > sizeof gspca_dev->usb_buf) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300415 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
416 return;
417 }
418#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300419 memcpy(gspca_dev->usb_buf, buffer, len);
420 usb_control_msg(gspca_dev->dev,
421 usb_sndctrlpipe(gspca_dev->dev, 0),
422 0x08, /* request */
423 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
424 value,
425 0, /* index */
426 gspca_dev->usb_buf, len,
427 500);
428}
429
430static void reg_w_big(struct gspca_dev *gspca_dev,
431 __u16 value,
432 const __u8 *buffer,
433 int len)
434{
435 __u8 *tmpbuf;
436
437 tmpbuf = kmalloc(len, GFP_KERNEL);
Hans de Goede0d2a7222008-07-03 08:15:22 -0300438 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300439 usb_control_msg(gspca_dev->dev,
440 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300441 0x08, /* request */
442 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
443 value,
444 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300445 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300446 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300447 kfree(tmpbuf);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300448}
449
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300450static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300451{
452 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300453
454 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300455 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300456 while (retry--) {
457 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300458 reg_r(gspca_dev, 0x08);
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300459 if (gspca_dev->usb_buf[0] & 0x04) {
460 if (gspca_dev->usb_buf[0] & 0x08)
461 return -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300462 return 0;
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300463 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300464 }
465 return -1;
466}
467
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300468static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300469 const __u8 buffer[][8], int len)
470{
471 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300472 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300473 len -= 8;
474 if (len <= 0)
475 break;
476 buffer++;
477 }
478}
479
480static void setbrightness(struct gspca_dev *gspca_dev)
481{
482 struct sd *sd = (struct sd *) gspca_dev;
483 __u8 value;
484
485 switch (sd->sensor) {
Hans de Goedea975a522008-07-16 15:29:11 -0300486 case SENSOR_OV6650:
Andoni Zubimendi794af522008-07-16 08:33:14 -0300487 case SENSOR_OV7630_3:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300488 case SENSOR_OV7630: {
489 __u8 i2cOV[] =
Hans de Goedea975a522008-07-16 15:29:11 -0300490 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300491
492 /* change reg 0x06 */
Hans de Goedea975a522008-07-16 15:29:11 -0300493 i2cOV[1] = sd->sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300494 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300495 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300496 goto err;
497 break;
498 }
499 case SENSOR_PAS106: {
500 __u8 i2c1[] =
501 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
502
503 i2c1[3] = sd->brightness >> 3;
504 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300505 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506 goto err;
507 i2c1[3] = 0x01;
508 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300509 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300510 goto err;
511 break;
512 }
513 case SENSOR_PAS202: {
514 /* __u8 i2cpexpo1[] =
515 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
516 __u8 i2cpexpo[] =
517 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
518 __u8 i2cp202[] =
519 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
520 static __u8 i2cpdoit[] =
521 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
522
523 /* change reg 0x10 */
524 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300525/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300526 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300527/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300528 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300529 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300530 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300531 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532 goto err;
533 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300534 if (i2c_w(gspca_dev, i2cp202) < 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, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300537 goto err;
538 break;
539 }
Hans de Goededcef3232008-07-10 10:40:53 -0300540 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300541 __u8 i2c[] =
542 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
543
544 value = 0xff - sd->brightness;
545 i2c[4] = value;
546 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300547 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300548 goto err;
549 break;
550 }
Hans de Goededcef3232008-07-10 10:40:53 -0300551 case SENSOR_TAS5110:
552 /* FIXME figure out howto control brightness on TAS5110 */
553 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300554 }
555 return;
556err:
557 PDEBUG(D_ERR, "i2c error brightness");
558}
Hans de Goededcef3232008-07-10 10:40:53 -0300559
560static void setsensorgain(struct gspca_dev *gspca_dev)
561{
562 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea975a522008-07-16 15:29:11 -0300563 unsigned char gain = sd->gain;
Hans de Goededcef3232008-07-10 10:40:53 -0300564
565 switch (sd->sensor) {
566
567 case SENSOR_TAS5110: {
568 __u8 i2c[] =
569 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
570
Hans de Goedea975a522008-07-16 15:29:11 -0300571 i2c[4] = 255 - gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300572 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300573 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300574 break;
575 }
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300576
Hans de Goedea975a522008-07-16 15:29:11 -0300577 case SENSOR_OV6650:
578 gain >>= 1;
579 /* fall thru */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300580 case SENSOR_OV7630_3: {
Hans de Goedea975a522008-07-16 15:29:11 -0300581 __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Andoni Zubimendi794af522008-07-16 08:33:14 -0300582
Hans de Goedea975a522008-07-16 15:29:11 -0300583 i2c[1] = sd->sensor_addr;
584 i2c[3] = gain >> 2;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300585 if (i2c_w(gspca_dev, i2c) < 0)
586 goto err;
587 break;
588 }
Hans de Goededcef3232008-07-10 10:40:53 -0300589 }
590 return;
591err:
592 PDEBUG(D_ERR, "i2c error gain");
593}
594
595static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300596{
597 struct sd *sd = (struct sd *) gspca_dev;
598 __u8 gain;
599 __u8 rgb_value;
600
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300601 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300602
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300603 /* red and blue gain */
604 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300605 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300606 /* green gain */
607 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300608 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300609
610 if (sd->sensor_has_gain)
611 setsensorgain(gspca_dev);
612}
613
614static void setexposure(struct gspca_dev *gspca_dev)
615{
616 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300617
618 switch (sd->sensor) {
619 case SENSOR_TAS5110: {
620 __u8 reg;
621
622 /* register 19's high nibble contains the sn9c10x clock divider
623 The high nibble configures the no fps according to the
624 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300625 reg = 120 * sd->exposure / 1000;
626 if (reg < 2)
627 reg = 2;
628 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300629 reg = 15;
630 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300631 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300632 break;
633 }
Hans de Goedea975a522008-07-16 15:29:11 -0300634 case SENSOR_OV6650:
635 case SENSOR_OV7630_3: {
636 /* The ov6650 / ov7630 have 2 registers which both influence
637 exposure, register 11, whose low nibble sets the nr off fps
Hans de Goedef4d52022008-07-15 09:36:42 -0300638 according to: fps = 30 / (low_nibble + 1)
639
640 The fps configures the maximum exposure setting, but it is
641 possible to use less exposure then what the fps maximum
642 allows by setting register 10. register 10 configures the
643 actual exposure as quotient of the full exposure, with 0
644 being no exposure at all (not very usefull) and reg10_max
645 being max exposure possible at that framerate.
646
647 The code maps our 0 - 510 ms exposure ctrl to these 2
648 registers, trying to keep fps as high as possible.
649 */
Hans de Goedea975a522008-07-16 15:29:11 -0300650 __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
Hans de Goedef4d52022008-07-15 09:36:42 -0300651 int reg10, reg11;
Hans de Goede66f35822008-07-16 10:16:28 -0300652 /* ov6645 datasheet says reg10_max is 9a, but that uses
653 tline * 2 * reg10 as formula for calculating texpo, the
654 ov6650 probably uses the same formula as the 7730 which uses
655 tline * 4 * reg10, which explains why the reg10max we've
656 found experimentally for the ov6650 is exactly half that of
Hans de Goedea975a522008-07-16 15:29:11 -0300657 the ov6645. The ov7630 datasheet says the max is 0x41. */
658 const int reg10_max = (sd->sensor == SENSOR_OV6650)? 0x4d:0x41;
Hans de Goedef4d52022008-07-15 09:36:42 -0300659
660 reg11 = (60 * sd->exposure + 999) / 1000;
661 if (reg11 < 1)
662 reg11 = 1;
663 else if (reg11 > 16)
664 reg11 = 16;
665
666 /* frame exposure time in ms = 1000 * reg11 / 30 ->
667 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
668 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
Hans de Goedea975a522008-07-16 15:29:11 -0300669
670 /* Don't allow this to get below 10 when using autogain, the
671 steps become very large (relatively) when below 10 causing
672 the image to oscilate from much too dark, to much too bright
673 and back again. */
674 if (sd->autogain && reg10 < 10)
675 reg10 = 10;
Hans de Goedef4d52022008-07-15 09:36:42 -0300676 else if (reg10 > reg10_max)
677 reg10 = reg10_max;
678
679 /* Write reg 10 and reg11 low nibble */
Hans de Goedea975a522008-07-16 15:29:11 -0300680 i2c[1] = sd->sensor_addr;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300681 i2c[3] = reg10;
682 i2c[4] |= reg11 - 1;
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300683 if (sd->sensor == SENSOR_OV7630_3) {
684 __u8 reg76 = reg10 & 0x03;
685 __u8 i2c_reg76[] = {0xa0, 0x21, 0x76, 0x00,
686 0x00, 0x00, 0x00, 0x10};
687 reg10 >>= 2;
688 i2c_reg76[3] = reg76;
689 if (i2c_w(gspca_dev, i2c_reg76) < 0)
690 PDEBUG(D_ERR, "i2c error exposure");
691 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300692 if (i2c_w(gspca_dev, i2c) < 0)
693 PDEBUG(D_ERR, "i2c error exposure");
694 break;
695 }
Hans de Goededcef3232008-07-10 10:40:53 -0300696 }
697}
698
Hans de Goede66f35822008-07-16 10:16:28 -0300699static void setfreq(struct gspca_dev *gspca_dev)
700{
701 struct sd *sd = (struct sd *) gspca_dev;
702
703 switch (sd->sensor) {
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300704 case SENSOR_OV6650:
705 case SENSOR_OV7630_3: {
Hans de Goede66f35822008-07-16 10:16:28 -0300706 /* Framerate adjust register for artificial light 50 hz flicker
707 compensation, identical to ov6630 0x2b register, see ov6630
708 datasheet.
709 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300710 __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goede66f35822008-07-16 10:16:28 -0300711 switch (sd->freq) {
712 default:
713/* case 0: * no filter*/
714/* case 2: * 60 hz */
715 i2c[3] = 0;
716 break;
717 case 1: /* 50 hz */
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300718 i2c[3] = (sd->sensor == SENSOR_OV6650)? 0x4f:0x8a;
Hans de Goede66f35822008-07-16 10:16:28 -0300719 break;
720 }
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300721 i2c[1] = sd->sensor_addr;
Hans de Goede66f35822008-07-16 10:16:28 -0300722 if (i2c_w(gspca_dev, i2c) < 0)
723 PDEBUG(D_ERR, "i2c error setfreq");
724 break;
725 }
726 }
727}
728
Hans de Goededcef3232008-07-10 10:40:53 -0300729
730static void do_autogain(struct gspca_dev *gspca_dev)
731{
732 struct sd *sd = (struct sd *) gspca_dev;
733 int avg_lum = atomic_read(&sd->avg_lum);
734
735 if (avg_lum == -1)
736 return;
737
738 if (sd->autogain_ignore_frames > 0)
739 sd->autogain_ignore_frames--;
740 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
741 sd->brightness * DESIRED_AVG_LUM / 127,
Hans de Goedea975a522008-07-16 15:29:11 -0300742 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
743 PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
744 (int)sd->gain, (int)sd->exposure);
Hans de Goededcef3232008-07-10 10:40:53 -0300745 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Hans de Goedea975a522008-07-16 15:29:11 -0300746 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300747}
748
749/* this function is called at probe time */
750static int sd_config(struct gspca_dev *gspca_dev,
751 const struct usb_device_id *id)
752{
753 struct sd *sd = (struct sd *) gspca_dev;
754 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300755 __u16 product;
756 int sif = 0;
757
Hans de Goededcef3232008-07-10 10:40:53 -0300758 /* nctrls depends upon the sensor, so we use a per cam copy */
759 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
760 gspca_dev->sd_desc = &sd->sd_desc;
761
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300762 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300763 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300764 sd->autogain = AUTOGAIN_DEF; /* default is autogain active */
Hans de Goede66f35822008-07-16 10:16:28 -0300765 sd->freq = FREQ_DEF;
Hans de Goededcef3232008-07-10 10:40:53 -0300766
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300767 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300768/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300769/* case 0x0c45: * Sonix */
770 switch (product) {
771 case 0x6001: /* SN9C102 */
772 case 0x6005: /* SN9C101 */
773 case 0x6007: /* SN9C101 */
774 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300775 sd->sensor_has_gain = 1;
776 sd->sd_desc.nctrls = 4;
777 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300778 sif = 1;
779 break;
780 case 0x6009: /* SN9C101 */
781 case 0x600d: /* SN9C101 */
782 case 0x6029: /* SN9C101 */
783 sd->sensor = SENSOR_PAS106;
784 sif = 1;
785 break;
786 case 0x6011: /* SN9C101 - SN9C101G */
787 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300788 sd->sensor_has_gain = 1;
Hans de Goedea975a522008-07-16 15:29:11 -0300789 sd->sensor_addr = 0x60;
Hans de Goededcef3232008-07-10 10:40:53 -0300790 sd->sd_desc.nctrls = 4;
791 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300792 sif = 1;
793 break;
794 case 0x6019: /* SN9C101 */
795 case 0x602c: /* SN9C102 */
796 case 0x602e: /* SN9C102 */
797 sd->sensor = SENSOR_OV7630;
Hans de Goedea975a522008-07-16 15:29:11 -0300798 sd->sensor_addr = 0x21;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300799 break;
800 case 0x60b0: /* SN9C103 */
801 sd->sensor = SENSOR_OV7630_3;
Hans de Goedea975a522008-07-16 15:29:11 -0300802 sd->sensor_addr = 0x21;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300803 sd->fr_h_sz = 18; /* size of frame header */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300804 sd->sensor_has_gain = 1;
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300805 sd->sd_desc.nctrls = 5;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300806 sd->sd_desc.dq_callback = do_autogain;
807 sd->autogain = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300808 break;
809 case 0x6024: /* SN9C102 */
810 case 0x6025: /* SN9C102 */
811 sd->sensor = SENSOR_TAS5130CXX;
812 break;
813 case 0x6028: /* SN9C102 */
814 sd->sensor = SENSOR_PAS202;
815 break;
816 case 0x602d: /* SN9C102 */
817 sd->sensor = SENSOR_HV7131R;
818 break;
819 case 0x60af: /* SN9C103 */
820 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300821 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300822 break;
823 }
824/* break; */
825/* } */
826
827 cam = &gspca_dev->cam;
828 cam->dev_name = (char *) id->driver_info;
829 cam->epaddr = 0x01;
830 if (!sif) {
831 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300832 cam->nmodes = ARRAY_SIZE(vga_mode);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300833 if (sd->sensor == SENSOR_OV7630_3) {
834 /* We only have 320x240 & 640x480 */
835 cam->cam_mode++;
836 cam->nmodes--;
837 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300838 } else {
839 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300840 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300841 }
Hans de Goededcef3232008-07-10 10:40:53 -0300842 sd->brightness = BRIGHTNESS_DEF;
843 sd->gain = GAIN_DEF;
844 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300845 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300846 reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300847 return 0;
848}
849
850/* this function is called at open time */
851static int sd_open(struct gspca_dev *gspca_dev)
852{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300853 reg_r(gspca_dev, 0x00);
854 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300855 return -ENODEV;
856 return 0;
857}
858
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300859static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300860{
861 int i;
862 const __u8 *data;
863 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
864
865 i = ARRAY_SIZE(pas106_data);
866 data = pas106_data[0];
867 while (--i >= 0) {
868 memcpy(&i2c1[2], data, 2);
869 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300870 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300871 PDEBUG(D_ERR, "i2c error pas106");
872 data += 2;
873 }
874}
875
876/* -- start the camera -- */
877static void sd_start(struct gspca_dev *gspca_dev)
878{
879 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300880 int mode, l;
881 const __u8 *sn9c10x;
882 __u8 reg01, reg17;
883 __u8 reg17_19[3];
884
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300885 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300886 switch (sd->sensor) {
887 case SENSOR_HV7131R:
888 sn9c10x = initHv7131;
889 reg17_19[0] = 0x60;
890 reg17_19[1] = (mode << 4) | 0x8a;
891 reg17_19[2] = 0x20;
892 break;
893 case SENSOR_OV6650:
894 sn9c10x = initOv6650;
895 reg17_19[0] = 0x68;
896 reg17_19[1] = (mode << 4) | 0x8b;
897 reg17_19[2] = 0x20;
898 break;
899 case SENSOR_OV7630:
900 sn9c10x = initOv7630;
901 reg17_19[0] = 0x68;
902 reg17_19[1] = (mode << 4) | COMP2;
903 reg17_19[2] = MCK_INIT1;
904 break;
905 case SENSOR_OV7630_3:
906 sn9c10x = initOv7630_3;
907 reg17_19[0] = 0x68;
908 reg17_19[1] = (mode << 4) | COMP2;
909 reg17_19[2] = MCK_INIT1;
910 break;
911 case SENSOR_PAS106:
912 sn9c10x = initPas106;
913 reg17_19[0] = 0x24; /* 0x28 */
914 reg17_19[1] = (mode << 4) | COMP1;
915 reg17_19[2] = MCK_INIT1;
916 break;
917 case SENSOR_PAS202:
918 sn9c10x = initPas202;
919 reg17_19[0] = mode ? 0x24 : 0x20;
920 reg17_19[1] = (mode << 4) | 0x89;
921 reg17_19[2] = 0x20;
922 break;
923 case SENSOR_TAS5110:
924 sn9c10x = initTas5110;
925 reg17_19[0] = 0x60;
926 reg17_19[1] = (mode << 4) | 0x86;
927 reg17_19[2] = 0x2b; /* 0xf3; */
928 break;
929 default:
930/* case SENSOR_TAS5130CXX: */
931 sn9c10x = initTas5130;
932 reg17_19[0] = 0x60;
933 reg17_19[1] = (mode << 4) | COMP;
934 reg17_19[2] = mode ? 0x23 : 0x43;
935 break;
936 }
937 switch (sd->sensor) {
938 case SENSOR_OV7630:
939 reg01 = 0x06;
940 reg17 = 0x29;
941 l = 0x10;
942 break;
943 case SENSOR_OV7630_3:
944 reg01 = 0x44;
945 reg17 = 0x68;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300946 l = sizeof initOv7630_3;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300947 break;
948 default:
949 reg01 = sn9c10x[0];
950 reg17 = sn9c10x[0x17 - 1];
951 l = 0x1f;
952 break;
953 }
954
955 /* reg 0x01 bit 2 video transfert on */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300956 reg_w(gspca_dev, 0x01, &reg01, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300957 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300958 reg_w(gspca_dev, 0x17, &reg17, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300959/*fixme: for ov7630 102
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300960 reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300961 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300962 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300963 switch (sd->sensor) {
964 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300965 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300966 sizeof hv7131_sensor_init);
967 break;
968 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300969 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300970 sizeof ov6650_sensor_init);
971 break;
972 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300973 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300974 sizeof ov7630_sensor_init_com);
975 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300976 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300977 sizeof ov7630_sensor_init);
978 break;
979 case SENSOR_OV7630_3:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300980 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300981 sizeof ov7630_sensor_init_com);
982 msleep(200);
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300983 i2c_w(gspca_dev, ov7630_sensor_init_3[mode]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300984 break;
985 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300986 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300987 break;
988 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300989 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300990 sizeof pas202_sensor_init);
991 break;
992 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300993 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300994 sizeof tas5110_sensor_init);
995 break;
996 default:
997/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300998 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300999 sizeof tas5130_sensor_init);
1000 break;
1001 }
Hans de Goede3647fea2008-07-15 05:36:30 -03001002 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
1003 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001004 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001005 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -03001006 /* H_start */
1007 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
1008 /* V_START */
1009 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001010 /* reset 0x17 SensorClk enable inv Clk 0x60 */
1011 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001012 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001013 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -03001014 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001015 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001016 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001017 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001018 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001019 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001020 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001021 msleep(20);
1022
Hans de Goededcef3232008-07-10 10:40:53 -03001023 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001024 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001025 setexposure(gspca_dev);
Hans de Goede66f35822008-07-16 10:16:28 -03001026 setfreq(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001027
1028 sd->autogain_ignore_frames = 0;
1029 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001030}
1031
1032static void sd_stopN(struct gspca_dev *gspca_dev)
1033{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -03001034 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001035
1036 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001037 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001038}
1039
1040static void sd_stop0(struct gspca_dev *gspca_dev)
1041{
1042}
1043
1044static void sd_close(struct gspca_dev *gspca_dev)
1045{
1046}
1047
1048static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1049 struct gspca_frame *frame, /* target */
1050 unsigned char *data, /* isoc packet */
1051 int len) /* iso packet length */
1052{
Hans de Goede0d2a7222008-07-03 08:15:22 -03001053 int i;
Hans de Goededcef3232008-07-10 10:40:53 -03001054 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001055
Hans de Goedec36260ee2008-07-16 09:56:07 -03001056 /* frames start with:
1057 * ff ff 00 c4 c4 96 synchro
1058 * 00 (unknown)
1059 * xx (frame sequence / size / compression)
1060 * (xx) (idem - extra byte for sn9c103)
1061 * ll mm brightness sum inside auto exposure
1062 * ll mm brightness sum outside auto exposure
1063 * (xx xx xx xx xx) audio values for snc103
1064 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001065 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -03001066 for (i = 0; i < len - 6; i++) {
1067 if (data[0 + i] == 0xff
1068 && data[1 + i] == 0xff
1069 && data[2 + i] == 0x00
1070 && data[3 + i] == 0xc4
1071 && data[4 + i] == 0xc4
1072 && data[5 + i] == 0x96) { /* start of frame */
1073 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
1074 frame, data, 0);
Hans de Goedec36260ee2008-07-16 09:56:07 -03001075 if (len - i < sd->fr_h_sz) {
1076 atomic_set(&sd->avg_lum, -1);
1077 PDEBUG(D_STREAM, "packet too short to"
1078 " get avg brightness");
1079 } else if (sd->fr_h_sz == 12) {
1080 atomic_set(&sd->avg_lum,
1081 data[i + 8] +
Hans de Goededcef3232008-07-10 10:40:53 -03001082 (data[i + 9] << 8));
1083 } else {
Hans de Goedec36260ee2008-07-16 09:56:07 -03001084 atomic_set(&sd->avg_lum,
1085 data[i + 9] +
1086 (data[i + 10] << 8));
Hans de Goededcef3232008-07-10 10:40:53 -03001087 }
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -03001088 data += i + sd->fr_h_sz;
1089 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001090 gspca_frame_add(gspca_dev, FIRST_PACKET,
1091 frame, data, len);
1092 return;
1093 }
1094 }
1095 }
1096 gspca_frame_add(gspca_dev, INTER_PACKET,
1097 frame, data, len);
1098}
1099
1100static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1101{
1102 struct sd *sd = (struct sd *) gspca_dev;
1103
1104 sd->brightness = val;
1105 if (gspca_dev->streaming)
1106 setbrightness(gspca_dev);
1107 return 0;
1108}
1109
1110static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1111{
1112 struct sd *sd = (struct sd *) gspca_dev;
1113
1114 *val = sd->brightness;
1115 return 0;
1116}
1117
Hans de Goededcef3232008-07-10 10:40:53 -03001118static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001119{
1120 struct sd *sd = (struct sd *) gspca_dev;
1121
Hans de Goededcef3232008-07-10 10:40:53 -03001122 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001123 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001124 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001125 return 0;
1126}
1127
Hans de Goededcef3232008-07-10 10:40:53 -03001128static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001129{
1130 struct sd *sd = (struct sd *) gspca_dev;
1131
Hans de Goededcef3232008-07-10 10:40:53 -03001132 *val = sd->gain;
1133 return 0;
1134}
1135
1136static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1137{
1138 struct sd *sd = (struct sd *) gspca_dev;
1139
1140 sd->exposure = val;
1141 if (gspca_dev->streaming)
1142 setexposure(gspca_dev);
1143 return 0;
1144}
1145
1146static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1147{
1148 struct sd *sd = (struct sd *) gspca_dev;
1149
1150 *val = sd->exposure;
1151 return 0;
1152}
1153
1154static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1155{
1156 struct sd *sd = (struct sd *) gspca_dev;
1157
1158 sd->autogain = val;
1159 /* when switching to autogain set defaults to make sure
1160 we are on a valid point of the autogain gain /
1161 exposure knee graph, and give this change time to
1162 take effect before doing autogain. */
1163 if (sd->autogain) {
1164 sd->exposure = EXPOSURE_DEF;
1165 sd->gain = GAIN_DEF;
1166 if (gspca_dev->streaming) {
1167 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1168 setexposure(gspca_dev);
1169 setgain(gspca_dev);
1170 }
1171 }
1172
1173 return 0;
1174}
1175
1176static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1177{
1178 struct sd *sd = (struct sd *) gspca_dev;
1179
1180 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001181 return 0;
1182}
1183
Hans de Goede66f35822008-07-16 10:16:28 -03001184static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1185{
1186 struct sd *sd = (struct sd *) gspca_dev;
1187
1188 sd->freq = val;
1189 if (gspca_dev->streaming)
1190 setfreq(gspca_dev);
1191 return 0;
1192}
1193
1194static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1195{
1196 struct sd *sd = (struct sd *) gspca_dev;
1197
1198 *val = sd->freq;
1199 return 0;
1200}
1201
1202static int sd_querymenu(struct gspca_dev *gspca_dev,
1203 struct v4l2_querymenu *menu)
1204{
1205 switch (menu->id) {
1206 case V4L2_CID_POWER_LINE_FREQUENCY:
1207 switch (menu->index) {
1208 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1209 strcpy((char *) menu->name, "NoFliker");
1210 return 0;
1211 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1212 strcpy((char *) menu->name, "50 Hz");
1213 return 0;
1214 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1215 strcpy((char *) menu->name, "60 Hz");
1216 return 0;
1217 }
1218 break;
1219 }
1220 return -EINVAL;
1221}
1222
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001223/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001224static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001225 .name = MODULE_NAME,
1226 .ctrls = sd_ctrls,
1227 .nctrls = ARRAY_SIZE(sd_ctrls),
1228 .config = sd_config,
1229 .open = sd_open,
1230 .start = sd_start,
1231 .stopN = sd_stopN,
1232 .stop0 = sd_stop0,
1233 .close = sd_close,
1234 .pkt_scan = sd_pkt_scan,
Hans de Goede66f35822008-07-16 10:16:28 -03001235 .querymenu = sd_querymenu,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001236};
1237
1238/* -- module initialisation -- */
1239#define DVNM(name) .driver_info = (kernel_ulong_t) name
1240static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001241#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001242 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1243 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1244 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1245 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1246 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001247 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001248 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1249 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1250 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1251 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1252 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1253 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1254 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1255 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1256 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1257 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001258#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001259 {}
1260};
1261MODULE_DEVICE_TABLE(usb, device_table);
1262
1263/* -- device connect -- */
1264static int sd_probe(struct usb_interface *intf,
1265 const struct usb_device_id *id)
1266{
1267 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1268 THIS_MODULE);
1269}
1270
1271static struct usb_driver sd_driver = {
1272 .name = MODULE_NAME,
1273 .id_table = device_table,
1274 .probe = sd_probe,
1275 .disconnect = gspca_disconnect,
1276};
1277
1278/* -- module insert / remove -- */
1279static int __init sd_mod_init(void)
1280{
1281 if (usb_register(&sd_driver) < 0)
1282 return -1;
1283 PDEBUG(D_PROBE, "v%s registered", version);
1284 return 0;
1285}
1286static void __exit sd_mod_exit(void)
1287{
1288 usb_deregister(&sd_driver);
1289 PDEBUG(D_PROBE, "deregistered");
1290}
1291
1292module_init(sd_mod_init);
1293module_exit(sd_mod_exit);