blob: 4625a464a547e996dd8b7917c00430a53c68546e [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 Zubimendi4b972d22008-07-14 09:50:26 -0300294static const __u8 ov7630_sensor_init_3[][5][8] = {
295 { {0xa0, 0x21, 0x10, 0x36, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
296 {0xa0, 0x21, 0x76, 0x03, 0xbd, 0x06, 0xf6, 0x16},
297 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x16},
298 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
299 {0xb0, 0x21, 0x2a, 0xa0, 0x1c, 0x06, 0xf6, 0x1d},
300 },
301 { {0xa0, 0x21, 0x10, 0x83, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300302 {0xa0, 0x21, 0x76, 0x00, 0xbd, 0x06, 0xf6, 0x16},
303 {0xa0, 0x21, 0x11, 0x00, 0xbd, 0x06, 0xf6, 0x16},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300304 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
305/* {0xb0, 0x21, 0x2a, 0xc0, 0x3c, 0x06, 0xf6, 0x1d},
306 * a0 1c,a0 1f,c0 3c frame rate ?line interval from ov6630 */
307/* {0xb0, 0x21, 0x2a, 0xa0, 0x1f, 0x06, 0xf6, 0x1d}, * from win */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300308 {0xb0, 0x21, 0x2a, 0x80, 0x60, 0x06, 0xf6, 0x1d},
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300309 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300310};
311
312static const __u8 initPas106[] = {
313 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
314 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
316 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
317 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
318};
319/* compression 0x86 mckinit1 0x2b */
320static const __u8 pas106_data[][2] = {
321 {0x02, 0x04}, /* Pixel Clock Divider 6 */
322 {0x03, 0x13}, /* Frame Time MSB */
323/* {0x03, 0x12}, * Frame Time MSB */
324 {0x04, 0x06}, /* Frame Time LSB */
325/* {0x04, 0x05}, * Frame Time LSB */
326 {0x05, 0x65}, /* Shutter Time Line Offset */
327/* {0x05, 0x6d}, * Shutter Time Line Offset */
328/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
329 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
330 {0x07, 0xc1}, /* Black Level Subtract Sign */
331/* {0x07, 0x00}, * Black Level Subtract Sign */
332 {0x08, 0x06}, /* Black Level Subtract Level */
333 {0x08, 0x06}, /* Black Level Subtract Level */
334/* {0x08, 0x01}, * Black Level Subtract Level */
335 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
336 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
337 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
338 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
339 {0x0d, 0x00}, /* Color GainH Pixel */
340 {0x0e, 0x0e}, /* Global Gain */
341 {0x0f, 0x00}, /* Contrast */
342 {0x10, 0x06}, /* H&V synchro polarity */
343 {0x11, 0x06}, /* ?default */
344 {0x12, 0x06}, /* DAC scale */
345 {0x14, 0x02}, /* ?default */
346 {0x13, 0x01}, /* Validate Settings */
347};
348static const __u8 initPas202[] = {
349 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
350 0x00, 0x00,
351 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
352 0x28, 0x1e, 0x28, 0x89, 0x30,
353 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
354};
355static const __u8 pas202_sensor_init[][8] = {
356 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
357 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
358 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
359 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
360 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
361 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
362 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
363 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
364 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
365 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
366 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
367 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
368
369 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
370 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
371 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
372 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
373 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
374 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
375 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
376 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
377};
378
379static const __u8 initTas5110[] = {
380 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
381 0x00, 0x00,
382 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
383 0x16, 0x12, 0x60, 0x86, 0x2b,
384 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
385};
386static const __u8 tas5110_sensor_init[][8] = {
387 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
388 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
389 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
390};
391
392static const __u8 initTas5130[] = {
393 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
394 0x00, 0x00,
395 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
396 0x28, 0x1e, 0x60, COMP, MCK_INIT,
397 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
398};
399static const __u8 tas5130_sensor_init[][8] = {
400/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
401 * shutter 0x47 short exposure? */
402 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
403 /* shutter 0x01 long exposure */
404 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
405};
406
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300407/* get one byte in gspca_dev->usb_buf */
408static void reg_r(struct gspca_dev *gspca_dev,
409 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300410{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300411 usb_control_msg(gspca_dev->dev,
412 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300413 0, /* request */
414 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
415 value,
416 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300417 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300418 500);
419}
420
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300421static void reg_w(struct gspca_dev *gspca_dev,
422 __u16 value,
423 const __u8 *buffer,
424 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300425{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300426#ifdef CONFIG_VIDEO_ADV_DEBUG
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300427 if (len > sizeof gspca_dev->usb_buf) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300428 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
429 return;
430 }
431#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300432 memcpy(gspca_dev->usb_buf, buffer, len);
433 usb_control_msg(gspca_dev->dev,
434 usb_sndctrlpipe(gspca_dev->dev, 0),
435 0x08, /* request */
436 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
437 value,
438 0, /* index */
439 gspca_dev->usb_buf, len,
440 500);
441}
442
443static void reg_w_big(struct gspca_dev *gspca_dev,
444 __u16 value,
445 const __u8 *buffer,
446 int len)
447{
448 __u8 *tmpbuf;
449
450 tmpbuf = kmalloc(len, GFP_KERNEL);
Hans de Goede0d2a7222008-07-03 08:15:22 -0300451 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300452 usb_control_msg(gspca_dev->dev,
453 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300454 0x08, /* request */
455 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
456 value,
457 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300458 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300459 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300460 kfree(tmpbuf);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300461}
462
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300463static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300464{
465 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300466
467 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300468 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300469 while (retry--) {
470 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300471 reg_r(gspca_dev, 0x08);
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300472 if (gspca_dev->usb_buf[0] & 0x04) {
473 if (gspca_dev->usb_buf[0] & 0x08)
474 return -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300475 return 0;
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300476 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300477 }
478 return -1;
479}
480
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300481static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300482 const __u8 buffer[][8], int len)
483{
484 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300485 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300486 len -= 8;
487 if (len <= 0)
488 break;
489 buffer++;
490 }
491}
492
493static void setbrightness(struct gspca_dev *gspca_dev)
494{
495 struct sd *sd = (struct sd *) gspca_dev;
496 __u8 value;
497
498 switch (sd->sensor) {
Hans de Goedea975a522008-07-16 15:29:11 -0300499 case SENSOR_OV6650:
Andoni Zubimendi794af522008-07-16 08:33:14 -0300500 case SENSOR_OV7630_3:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300501 case SENSOR_OV7630: {
502 __u8 i2cOV[] =
Hans de Goedea975a522008-07-16 15:29:11 -0300503 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300504
505 /* change reg 0x06 */
Hans de Goedea975a522008-07-16 15:29:11 -0300506 i2cOV[1] = sd->sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300507 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300508 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300509 goto err;
510 break;
511 }
512 case SENSOR_PAS106: {
513 __u8 i2c1[] =
514 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
515
516 i2c1[3] = sd->brightness >> 3;
517 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300518 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300519 goto err;
520 i2c1[3] = 0x01;
521 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300522 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300523 goto err;
524 break;
525 }
526 case SENSOR_PAS202: {
527 /* __u8 i2cpexpo1[] =
528 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
529 __u8 i2cpexpo[] =
530 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
531 __u8 i2cp202[] =
532 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
533 static __u8 i2cpdoit[] =
534 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
535
536 /* change reg 0x10 */
537 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300538/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300539 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300540/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300541 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300542 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300543 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300544 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300545 goto err;
546 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300547 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300548 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300549 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300550 goto err;
551 break;
552 }
Hans de Goededcef3232008-07-10 10:40:53 -0300553 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300554 __u8 i2c[] =
555 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
556
557 value = 0xff - sd->brightness;
558 i2c[4] = value;
559 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300560 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300561 goto err;
562 break;
563 }
Hans de Goededcef3232008-07-10 10:40:53 -0300564 case SENSOR_TAS5110:
565 /* FIXME figure out howto control brightness on TAS5110 */
566 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300567 }
568 return;
569err:
570 PDEBUG(D_ERR, "i2c error brightness");
571}
Hans de Goededcef3232008-07-10 10:40:53 -0300572
573static void setsensorgain(struct gspca_dev *gspca_dev)
574{
575 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea975a522008-07-16 15:29:11 -0300576 unsigned char gain = sd->gain;
Hans de Goededcef3232008-07-10 10:40:53 -0300577
578 switch (sd->sensor) {
579
580 case SENSOR_TAS5110: {
581 __u8 i2c[] =
582 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
583
Hans de Goedea975a522008-07-16 15:29:11 -0300584 i2c[4] = 255 - gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300585 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300586 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300587 break;
588 }
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300589
Hans de Goedea975a522008-07-16 15:29:11 -0300590 case SENSOR_OV6650:
591 gain >>= 1;
592 /* fall thru */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300593 case SENSOR_OV7630_3: {
Hans de Goedea975a522008-07-16 15:29:11 -0300594 __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Andoni Zubimendi794af522008-07-16 08:33:14 -0300595
Hans de Goedea975a522008-07-16 15:29:11 -0300596 i2c[1] = sd->sensor_addr;
597 i2c[3] = gain >> 2;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300598 if (i2c_w(gspca_dev, i2c) < 0)
599 goto err;
600 break;
601 }
Hans de Goededcef3232008-07-10 10:40:53 -0300602 }
603 return;
604err:
605 PDEBUG(D_ERR, "i2c error gain");
606}
607
608static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300609{
610 struct sd *sd = (struct sd *) gspca_dev;
611 __u8 gain;
612 __u8 rgb_value;
613
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300614 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300615
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300616 /* red and blue gain */
617 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300618 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300619 /* green gain */
620 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300621 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300622
623 if (sd->sensor_has_gain)
624 setsensorgain(gspca_dev);
625}
626
627static void setexposure(struct gspca_dev *gspca_dev)
628{
629 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300630
631 switch (sd->sensor) {
632 case SENSOR_TAS5110: {
633 __u8 reg;
634
635 /* register 19's high nibble contains the sn9c10x clock divider
636 The high nibble configures the no fps according to the
637 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300638 reg = 120 * sd->exposure / 1000;
639 if (reg < 2)
640 reg = 2;
641 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300642 reg = 15;
643 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300644 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300645 break;
646 }
Hans de Goedea975a522008-07-16 15:29:11 -0300647 case SENSOR_OV6650:
648 case SENSOR_OV7630_3: {
649 /* The ov6650 / ov7630 have 2 registers which both influence
650 exposure, register 11, whose low nibble sets the nr off fps
Hans de Goedef4d52022008-07-15 09:36:42 -0300651 according to: fps = 30 / (low_nibble + 1)
652
653 The fps configures the maximum exposure setting, but it is
654 possible to use less exposure then what the fps maximum
655 allows by setting register 10. register 10 configures the
656 actual exposure as quotient of the full exposure, with 0
657 being no exposure at all (not very usefull) and reg10_max
658 being max exposure possible at that framerate.
659
660 The code maps our 0 - 510 ms exposure ctrl to these 2
661 registers, trying to keep fps as high as possible.
662 */
Hans de Goedea975a522008-07-16 15:29:11 -0300663 __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
Hans de Goedef4d52022008-07-15 09:36:42 -0300664 int reg10, reg11;
Hans de Goede66f35822008-07-16 10:16:28 -0300665 /* ov6645 datasheet says reg10_max is 9a, but that uses
666 tline * 2 * reg10 as formula for calculating texpo, the
667 ov6650 probably uses the same formula as the 7730 which uses
668 tline * 4 * reg10, which explains why the reg10max we've
669 found experimentally for the ov6650 is exactly half that of
Hans de Goedea975a522008-07-16 15:29:11 -0300670 the ov6645. The ov7630 datasheet says the max is 0x41. */
671 const int reg10_max = (sd->sensor == SENSOR_OV6650)? 0x4d:0x41;
Hans de Goedef4d52022008-07-15 09:36:42 -0300672
673 reg11 = (60 * sd->exposure + 999) / 1000;
674 if (reg11 < 1)
675 reg11 = 1;
676 else if (reg11 > 16)
677 reg11 = 16;
678
679 /* frame exposure time in ms = 1000 * reg11 / 30 ->
680 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
681 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
Hans de Goedea975a522008-07-16 15:29:11 -0300682
683 /* Don't allow this to get below 10 when using autogain, the
684 steps become very large (relatively) when below 10 causing
685 the image to oscilate from much too dark, to much too bright
686 and back again. */
687 if (sd->autogain && reg10 < 10)
688 reg10 = 10;
Hans de Goedef4d52022008-07-15 09:36:42 -0300689 else if (reg10 > reg10_max)
690 reg10 = reg10_max;
691
692 /* Write reg 10 and reg11 low nibble */
Hans de Goedea975a522008-07-16 15:29:11 -0300693 i2c[1] = sd->sensor_addr;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300694 i2c[3] = reg10;
695 i2c[4] |= reg11 - 1;
696 if (i2c_w(gspca_dev, i2c) < 0)
697 PDEBUG(D_ERR, "i2c error exposure");
698 break;
699 }
Hans de Goededcef3232008-07-10 10:40:53 -0300700 }
701}
702
Hans de Goede66f35822008-07-16 10:16:28 -0300703static void setfreq(struct gspca_dev *gspca_dev)
704{
705 struct sd *sd = (struct sd *) gspca_dev;
706
707 switch (sd->sensor) {
708 case SENSOR_OV6650: {
709 /* Framerate adjust register for artificial light 50 hz flicker
710 compensation, identical to ov6630 0x2b register, see ov6630
711 datasheet.
712 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
713 __u8 i2c[] = {0xa0, 0x60, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
714 switch (sd->freq) {
715 default:
716/* case 0: * no filter*/
717/* case 2: * 60 hz */
718 i2c[3] = 0;
719 break;
720 case 1: /* 50 hz */
721 i2c[3] = 0x4f;
722 break;
723 }
724 if (i2c_w(gspca_dev, i2c) < 0)
725 PDEBUG(D_ERR, "i2c error setfreq");
726 break;
727 }
728 }
729}
730
Hans de Goededcef3232008-07-10 10:40:53 -0300731
732static void do_autogain(struct gspca_dev *gspca_dev)
733{
734 struct sd *sd = (struct sd *) gspca_dev;
735 int avg_lum = atomic_read(&sd->avg_lum);
736
737 if (avg_lum == -1)
738 return;
739
740 if (sd->autogain_ignore_frames > 0)
741 sd->autogain_ignore_frames--;
742 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
743 sd->brightness * DESIRED_AVG_LUM / 127,
Hans de Goedea975a522008-07-16 15:29:11 -0300744 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
745 PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
746 (int)sd->gain, (int)sd->exposure);
Hans de Goededcef3232008-07-10 10:40:53 -0300747 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Hans de Goedea975a522008-07-16 15:29:11 -0300748 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300749}
750
751/* this function is called at probe time */
752static int sd_config(struct gspca_dev *gspca_dev,
753 const struct usb_device_id *id)
754{
755 struct sd *sd = (struct sd *) gspca_dev;
756 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300757 __u16 product;
758 int sif = 0;
759
Hans de Goededcef3232008-07-10 10:40:53 -0300760 /* nctrls depends upon the sensor, so we use a per cam copy */
761 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
762 gspca_dev->sd_desc = &sd->sd_desc;
763
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300764 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300765 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300766 sd->autogain = AUTOGAIN_DEF; /* default is autogain active */
Hans de Goede66f35822008-07-16 10:16:28 -0300767 sd->freq = FREQ_DEF;
Hans de Goededcef3232008-07-10 10:40:53 -0300768
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300769 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300770/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300771/* case 0x0c45: * Sonix */
772 switch (product) {
773 case 0x6001: /* SN9C102 */
774 case 0x6005: /* SN9C101 */
775 case 0x6007: /* SN9C101 */
776 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300777 sd->sensor_has_gain = 1;
778 sd->sd_desc.nctrls = 4;
779 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300780 sif = 1;
781 break;
782 case 0x6009: /* SN9C101 */
783 case 0x600d: /* SN9C101 */
784 case 0x6029: /* SN9C101 */
785 sd->sensor = SENSOR_PAS106;
786 sif = 1;
787 break;
788 case 0x6011: /* SN9C101 - SN9C101G */
789 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300790 sd->sensor_has_gain = 1;
Hans de Goedea975a522008-07-16 15:29:11 -0300791 sd->sensor_addr = 0x60;
Hans de Goededcef3232008-07-10 10:40:53 -0300792 sd->sd_desc.nctrls = 4;
793 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300794 sif = 1;
795 break;
796 case 0x6019: /* SN9C101 */
797 case 0x602c: /* SN9C102 */
798 case 0x602e: /* SN9C102 */
799 sd->sensor = SENSOR_OV7630;
Hans de Goedea975a522008-07-16 15:29:11 -0300800 sd->sensor_addr = 0x21;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300801 break;
802 case 0x60b0: /* SN9C103 */
803 sd->sensor = SENSOR_OV7630_3;
Hans de Goedea975a522008-07-16 15:29:11 -0300804 sd->sensor_addr = 0x21;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300805 sd->fr_h_sz = 18; /* size of frame header */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300806 sd->sensor_has_gain = 1;
807 sd->sd_desc.nctrls = 4;
808 sd->sd_desc.dq_callback = do_autogain;
809 sd->autogain = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300810 break;
811 case 0x6024: /* SN9C102 */
812 case 0x6025: /* SN9C102 */
813 sd->sensor = SENSOR_TAS5130CXX;
814 break;
815 case 0x6028: /* SN9C102 */
816 sd->sensor = SENSOR_PAS202;
817 break;
818 case 0x602d: /* SN9C102 */
819 sd->sensor = SENSOR_HV7131R;
820 break;
821 case 0x60af: /* SN9C103 */
822 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300823 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300824 break;
825 }
826/* break; */
827/* } */
828
829 cam = &gspca_dev->cam;
830 cam->dev_name = (char *) id->driver_info;
831 cam->epaddr = 0x01;
832 if (!sif) {
833 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300834 cam->nmodes = ARRAY_SIZE(vga_mode);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300835 if (sd->sensor == SENSOR_OV7630_3) {
836 /* We only have 320x240 & 640x480 */
837 cam->cam_mode++;
838 cam->nmodes--;
839 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300840 } else {
841 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300842 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300843 }
Hans de Goededcef3232008-07-10 10:40:53 -0300844 sd->brightness = BRIGHTNESS_DEF;
845 sd->gain = GAIN_DEF;
846 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300847 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300848 reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300849 return 0;
850}
851
852/* this function is called at open time */
853static int sd_open(struct gspca_dev *gspca_dev)
854{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300855 reg_r(gspca_dev, 0x00);
856 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300857 return -ENODEV;
858 return 0;
859}
860
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300861static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300862{
863 int i;
864 const __u8 *data;
865 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
866
867 i = ARRAY_SIZE(pas106_data);
868 data = pas106_data[0];
869 while (--i >= 0) {
870 memcpy(&i2c1[2], data, 2);
871 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300872 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300873 PDEBUG(D_ERR, "i2c error pas106");
874 data += 2;
875 }
876}
877
878/* -- start the camera -- */
879static void sd_start(struct gspca_dev *gspca_dev)
880{
881 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300882 int mode, l;
883 const __u8 *sn9c10x;
884 __u8 reg01, reg17;
885 __u8 reg17_19[3];
886
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300887 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300888 switch (sd->sensor) {
889 case SENSOR_HV7131R:
890 sn9c10x = initHv7131;
891 reg17_19[0] = 0x60;
892 reg17_19[1] = (mode << 4) | 0x8a;
893 reg17_19[2] = 0x20;
894 break;
895 case SENSOR_OV6650:
896 sn9c10x = initOv6650;
897 reg17_19[0] = 0x68;
898 reg17_19[1] = (mode << 4) | 0x8b;
899 reg17_19[2] = 0x20;
900 break;
901 case SENSOR_OV7630:
902 sn9c10x = initOv7630;
903 reg17_19[0] = 0x68;
904 reg17_19[1] = (mode << 4) | COMP2;
905 reg17_19[2] = MCK_INIT1;
906 break;
907 case SENSOR_OV7630_3:
908 sn9c10x = initOv7630_3;
909 reg17_19[0] = 0x68;
910 reg17_19[1] = (mode << 4) | COMP2;
911 reg17_19[2] = MCK_INIT1;
912 break;
913 case SENSOR_PAS106:
914 sn9c10x = initPas106;
915 reg17_19[0] = 0x24; /* 0x28 */
916 reg17_19[1] = (mode << 4) | COMP1;
917 reg17_19[2] = MCK_INIT1;
918 break;
919 case SENSOR_PAS202:
920 sn9c10x = initPas202;
921 reg17_19[0] = mode ? 0x24 : 0x20;
922 reg17_19[1] = (mode << 4) | 0x89;
923 reg17_19[2] = 0x20;
924 break;
925 case SENSOR_TAS5110:
926 sn9c10x = initTas5110;
927 reg17_19[0] = 0x60;
928 reg17_19[1] = (mode << 4) | 0x86;
929 reg17_19[2] = 0x2b; /* 0xf3; */
930 break;
931 default:
932/* case SENSOR_TAS5130CXX: */
933 sn9c10x = initTas5130;
934 reg17_19[0] = 0x60;
935 reg17_19[1] = (mode << 4) | COMP;
936 reg17_19[2] = mode ? 0x23 : 0x43;
937 break;
938 }
939 switch (sd->sensor) {
940 case SENSOR_OV7630:
941 reg01 = 0x06;
942 reg17 = 0x29;
943 l = 0x10;
944 break;
945 case SENSOR_OV7630_3:
946 reg01 = 0x44;
947 reg17 = 0x68;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300948 l = sizeof initOv7630_3;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300949 break;
950 default:
951 reg01 = sn9c10x[0];
952 reg17 = sn9c10x[0x17 - 1];
953 l = 0x1f;
954 break;
955 }
956
957 /* reg 0x01 bit 2 video transfert on */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300958 reg_w(gspca_dev, 0x01, &reg01, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300959 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300960 reg_w(gspca_dev, 0x17, &reg17, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300961/*fixme: for ov7630 102
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300962 reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300963 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300964 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300965 switch (sd->sensor) {
966 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300967 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300968 sizeof hv7131_sensor_init);
969 break;
970 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300971 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300972 sizeof ov6650_sensor_init);
973 break;
974 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300975 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300976 sizeof ov7630_sensor_init_com);
977 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300978 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300979 sizeof ov7630_sensor_init);
980 break;
981 case SENSOR_OV7630_3:
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);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300985 i2c_w_vector(gspca_dev, ov7630_sensor_init_3[mode],
986 sizeof ov7630_sensor_init_3[mode]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300987 break;
988 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300989 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300990 break;
991 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300992 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300993 sizeof pas202_sensor_init);
994 break;
995 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300996 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300997 sizeof tas5110_sensor_init);
998 break;
999 default:
1000/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001001 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001002 sizeof tas5130_sensor_init);
1003 break;
1004 }
Hans de Goede3647fea2008-07-15 05:36:30 -03001005 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
1006 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001007 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001008 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -03001009 /* H_start */
1010 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
1011 /* V_START */
1012 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001013 /* reset 0x17 SensorClk enable inv Clk 0x60 */
1014 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001015 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001016 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -03001017 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001018 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001019 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001020 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001021 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001022 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001023 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001024 msleep(20);
1025
Hans de Goededcef3232008-07-10 10:40:53 -03001026 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001027 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001028 setexposure(gspca_dev);
Hans de Goede66f35822008-07-16 10:16:28 -03001029 setfreq(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001030
1031 sd->autogain_ignore_frames = 0;
1032 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001033}
1034
1035static void sd_stopN(struct gspca_dev *gspca_dev)
1036{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -03001037 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001038
1039 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001040 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001041}
1042
1043static void sd_stop0(struct gspca_dev *gspca_dev)
1044{
1045}
1046
1047static void sd_close(struct gspca_dev *gspca_dev)
1048{
1049}
1050
1051static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1052 struct gspca_frame *frame, /* target */
1053 unsigned char *data, /* isoc packet */
1054 int len) /* iso packet length */
1055{
Hans de Goede0d2a7222008-07-03 08:15:22 -03001056 int i;
Hans de Goededcef3232008-07-10 10:40:53 -03001057 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001058
Hans de Goedec36260ee2008-07-16 09:56:07 -03001059 /* frames start with:
1060 * ff ff 00 c4 c4 96 synchro
1061 * 00 (unknown)
1062 * xx (frame sequence / size / compression)
1063 * (xx) (idem - extra byte for sn9c103)
1064 * ll mm brightness sum inside auto exposure
1065 * ll mm brightness sum outside auto exposure
1066 * (xx xx xx xx xx) audio values for snc103
1067 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001068 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -03001069 for (i = 0; i < len - 6; i++) {
1070 if (data[0 + i] == 0xff
1071 && data[1 + i] == 0xff
1072 && data[2 + i] == 0x00
1073 && data[3 + i] == 0xc4
1074 && data[4 + i] == 0xc4
1075 && data[5 + i] == 0x96) { /* start of frame */
1076 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
1077 frame, data, 0);
Hans de Goedec36260ee2008-07-16 09:56:07 -03001078 if (len - i < sd->fr_h_sz) {
1079 atomic_set(&sd->avg_lum, -1);
1080 PDEBUG(D_STREAM, "packet too short to"
1081 " get avg brightness");
1082 } else if (sd->fr_h_sz == 12) {
1083 atomic_set(&sd->avg_lum,
1084 data[i + 8] +
Hans de Goededcef3232008-07-10 10:40:53 -03001085 (data[i + 9] << 8));
1086 } else {
Hans de Goedec36260ee2008-07-16 09:56:07 -03001087 atomic_set(&sd->avg_lum,
1088 data[i + 9] +
1089 (data[i + 10] << 8));
Hans de Goededcef3232008-07-10 10:40:53 -03001090 }
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -03001091 data += i + sd->fr_h_sz;
1092 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001093 gspca_frame_add(gspca_dev, FIRST_PACKET,
1094 frame, data, len);
1095 return;
1096 }
1097 }
1098 }
1099 gspca_frame_add(gspca_dev, INTER_PACKET,
1100 frame, data, len);
1101}
1102
1103static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1104{
1105 struct sd *sd = (struct sd *) gspca_dev;
1106
1107 sd->brightness = val;
1108 if (gspca_dev->streaming)
1109 setbrightness(gspca_dev);
1110 return 0;
1111}
1112
1113static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1114{
1115 struct sd *sd = (struct sd *) gspca_dev;
1116
1117 *val = sd->brightness;
1118 return 0;
1119}
1120
Hans de Goededcef3232008-07-10 10:40:53 -03001121static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001122{
1123 struct sd *sd = (struct sd *) gspca_dev;
1124
Hans de Goededcef3232008-07-10 10:40:53 -03001125 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001126 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001127 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001128 return 0;
1129}
1130
Hans de Goededcef3232008-07-10 10:40:53 -03001131static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001132{
1133 struct sd *sd = (struct sd *) gspca_dev;
1134
Hans de Goededcef3232008-07-10 10:40:53 -03001135 *val = sd->gain;
1136 return 0;
1137}
1138
1139static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1140{
1141 struct sd *sd = (struct sd *) gspca_dev;
1142
1143 sd->exposure = val;
1144 if (gspca_dev->streaming)
1145 setexposure(gspca_dev);
1146 return 0;
1147}
1148
1149static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1150{
1151 struct sd *sd = (struct sd *) gspca_dev;
1152
1153 *val = sd->exposure;
1154 return 0;
1155}
1156
1157static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1158{
1159 struct sd *sd = (struct sd *) gspca_dev;
1160
1161 sd->autogain = val;
1162 /* when switching to autogain set defaults to make sure
1163 we are on a valid point of the autogain gain /
1164 exposure knee graph, and give this change time to
1165 take effect before doing autogain. */
1166 if (sd->autogain) {
1167 sd->exposure = EXPOSURE_DEF;
1168 sd->gain = GAIN_DEF;
1169 if (gspca_dev->streaming) {
1170 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1171 setexposure(gspca_dev);
1172 setgain(gspca_dev);
1173 }
1174 }
1175
1176 return 0;
1177}
1178
1179static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1180{
1181 struct sd *sd = (struct sd *) gspca_dev;
1182
1183 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001184 return 0;
1185}
1186
Hans de Goede66f35822008-07-16 10:16:28 -03001187static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1188{
1189 struct sd *sd = (struct sd *) gspca_dev;
1190
1191 sd->freq = val;
1192 if (gspca_dev->streaming)
1193 setfreq(gspca_dev);
1194 return 0;
1195}
1196
1197static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1198{
1199 struct sd *sd = (struct sd *) gspca_dev;
1200
1201 *val = sd->freq;
1202 return 0;
1203}
1204
1205static int sd_querymenu(struct gspca_dev *gspca_dev,
1206 struct v4l2_querymenu *menu)
1207{
1208 switch (menu->id) {
1209 case V4L2_CID_POWER_LINE_FREQUENCY:
1210 switch (menu->index) {
1211 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1212 strcpy((char *) menu->name, "NoFliker");
1213 return 0;
1214 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1215 strcpy((char *) menu->name, "50 Hz");
1216 return 0;
1217 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1218 strcpy((char *) menu->name, "60 Hz");
1219 return 0;
1220 }
1221 break;
1222 }
1223 return -EINVAL;
1224}
1225
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001226/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001227static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001228 .name = MODULE_NAME,
1229 .ctrls = sd_ctrls,
1230 .nctrls = ARRAY_SIZE(sd_ctrls),
1231 .config = sd_config,
1232 .open = sd_open,
1233 .start = sd_start,
1234 .stopN = sd_stopN,
1235 .stop0 = sd_stop0,
1236 .close = sd_close,
1237 .pkt_scan = sd_pkt_scan,
Hans de Goede66f35822008-07-16 10:16:28 -03001238 .querymenu = sd_querymenu,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001239};
1240
1241/* -- module initialisation -- */
1242#define DVNM(name) .driver_info = (kernel_ulong_t) name
1243static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001244#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001245 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1246 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1247 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1248 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1249 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001250 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001251 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1252 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1253 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1254 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1255 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1256 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1257 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1258 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1259 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1260 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001261#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001262 {}
1263};
1264MODULE_DEVICE_TABLE(usb, device_table);
1265
1266/* -- device connect -- */
1267static int sd_probe(struct usb_interface *intf,
1268 const struct usb_device_id *id)
1269{
1270 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1271 THIS_MODULE);
1272}
1273
1274static struct usb_driver sd_driver = {
1275 .name = MODULE_NAME,
1276 .id_table = device_table,
1277 .probe = sd_probe,
1278 .disconnect = gspca_disconnect,
1279};
1280
1281/* -- module insert / remove -- */
1282static int __init sd_mod_init(void)
1283{
1284 if (usb_register(&sd_driver) < 0)
1285 return -1;
1286 PDEBUG(D_PROBE, "v%s registered", version);
1287 return 0;
1288}
1289static void __exit sd_mod_exit(void)
1290{
1291 usb_deregister(&sd_driver);
1292 PDEBUG(D_PROBE, "deregistered");
1293}
1294
1295module_init(sd_mod_init);
1296module_exit(sd_mod_exit);