blob: e18748c5a14d4cf3df8a285586523824c10d22bf [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * sonix sn9c102 (bayer) library
3 * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
4 * Add Pas106 Stefano Mozzi (C) 2004
5 *
6 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#define MODULE_NAME "sonixb"
24
25#include "gspca.h"
26
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030027MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
28MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
29MODULE_LICENSE("GPL");
30
31/* specific webcam descriptor */
32struct sd {
33 struct gspca_dev gspca_dev; /* !! must be the first item */
34
Hans de Goededcef3232008-07-10 10:40:53 -030035 struct sd_desc sd_desc; /* our nctrls differ dependend upon the
36 sensor, so we use a per cam copy */
37 atomic_t avg_lum;
38
Hans de Goedead5ef80d2008-07-14 10:11:42 -030039 unsigned char gain;
40 unsigned char exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030041 unsigned char brightness;
Hans de Goededcef3232008-07-10 10:40:53 -030042 unsigned char autogain;
43 unsigned char autogain_ignore_frames;
Hans de Goede6af492e2008-07-22 07:09:33 -030044 unsigned char frames_to_drop;
Hans de Goede66f35822008-07-16 10:16:28 -030045 unsigned char freq; /* light freq filter setting */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030046
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -030047 unsigned char fr_h_sz; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030048 char sensor; /* Type of image sensor chip */
49#define SENSOR_HV7131R 0
50#define SENSOR_OV6650 1
51#define SENSOR_OV7630 2
Hans de Goede6af492e2008-07-22 07:09:33 -030052#define SENSOR_PAS106 3
53#define SENSOR_PAS202 4
54#define SENSOR_TAS5110 5
55#define SENSOR_TAS5130CXX 6
Hans de Goedea975a522008-07-16 15:29:11 -030056 char sensor_has_gain;
57 __u8 sensor_addr;
Hans de Goede6af492e2008-07-22 07:09:33 -030058 __u8 reg11;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030059};
60
Jean-Francois Moine5da162e2008-07-26 14:17:23 -030061/* flags used in the device id table */
62#define F_GAIN 0x01 /* has gain */
63#define F_AUTO 0x02 /* has autogain */
64#define F_SIF 0x04 /* sif or vga */
65#define F_H18 0x08 /* long (18 b) or short (12 b) frame header */
66
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030067#define COMP2 0x8f
68#define COMP 0xc7 /* 0x87 //0x07 */
69#define COMP1 0xc9 /* 0x89 //0x09 */
70
71#define MCK_INIT 0x63
72#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
73
74#define SYS_CLK 0x04
75
Hans de Goededcef3232008-07-10 10:40:53 -030076/* We calculate the autogain at the end of the transfer of a frame, at this
77 moment a frame with the old settings is being transmitted, and a frame is
78 being captured with the old settings. So if we adjust the autogain we must
79 ignore atleast the 2 next frames for the new settings to come into effect
80 before doing any other adjustments */
81#define AUTOGAIN_IGNORE_FRAMES 3
Hans de Goedead5ef80d2008-07-14 10:11:42 -030082#define AUTOGAIN_DEADZONE 1000
Hans de Goededcef3232008-07-10 10:40:53 -030083#define DESIRED_AVG_LUM 7000
84
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030085/* V4L2 controls supported by the driver */
86static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goededcef3232008-07-10 10:40:53 -030088static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
89static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
90static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
91static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
92static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
93static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede66f35822008-07-16 10:16:28 -030094static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
95static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030096
97static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030098 {
99 {
100 .id = V4L2_CID_BRIGHTNESS,
101 .type = V4L2_CTRL_TYPE_INTEGER,
102 .name = "Brightness",
103 .minimum = 0,
104 .maximum = 255,
105 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -0300106#define BRIGHTNESS_DEF 127
107 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300108 },
109 .set = sd_setbrightness,
110 .get = sd_getbrightness,
111 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300112 {
113 {
Hans de Goededcef3232008-07-10 10:40:53 -0300114 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300115 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300116 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300117 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300118 .maximum = 255,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300119 .step = 1,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300120#define GAIN_DEF 127
121#define GAIN_KNEE 200
Hans de Goededcef3232008-07-10 10:40:53 -0300122 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300123 },
Hans de Goededcef3232008-07-10 10:40:53 -0300124 .set = sd_setgain,
125 .get = sd_getgain,
126 },
Hans de Goededcef3232008-07-10 10:40:53 -0300127 {
128 {
129 .id = V4L2_CID_EXPOSURE,
130 .type = V4L2_CTRL_TYPE_INTEGER,
131 .name = "Exposure",
Hans de Goedef4d52022008-07-15 09:36:42 -0300132#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
133#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
Hans de Goededcef3232008-07-10 10:40:53 -0300134 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300135 .maximum = 255,
Hans de Goededcef3232008-07-10 10:40:53 -0300136 .step = 1,
137 .default_value = EXPOSURE_DEF,
138 .flags = 0,
139 },
140 .set = sd_setexposure,
141 .get = sd_getexposure,
142 },
Hans de Goededcef3232008-07-10 10:40:53 -0300143 {
144 {
145 .id = V4L2_CID_AUTOGAIN,
146 .type = V4L2_CTRL_TYPE_BOOLEAN,
147 .name = "Automatic Gain (and Exposure)",
148 .minimum = 0,
149 .maximum = 1,
150 .step = 1,
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300151#define AUTOGAIN_DEF 1
152 .default_value = AUTOGAIN_DEF,
Hans de Goededcef3232008-07-10 10:40:53 -0300153 .flags = 0,
154 },
155 .set = sd_setautogain,
156 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300157 },
Hans de Goede66f35822008-07-16 10:16:28 -0300158 {
159 {
160 .id = V4L2_CID_POWER_LINE_FREQUENCY,
161 .type = V4L2_CTRL_TYPE_MENU,
162 .name = "Light frequency filter",
163 .minimum = 0,
164 .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
165 .step = 1,
166#define FREQ_DEF 1
167 .default_value = FREQ_DEF,
168 },
169 .set = sd_setfreq,
170 .get = sd_getfreq,
171 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300172};
173
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300174static struct v4l2_pix_format vga_mode[] = {
175 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
176 .bytesperline = 160,
177 .sizeimage = 160 * 120,
178 .colorspace = V4L2_COLORSPACE_SRGB,
179 .priv = 2},
180 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
181 .bytesperline = 320,
182 .sizeimage = 320 * 240,
183 .colorspace = V4L2_COLORSPACE_SRGB,
184 .priv = 1},
185 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
186 .bytesperline = 640,
187 .sizeimage = 640 * 480,
188 .colorspace = V4L2_COLORSPACE_SRGB,
189 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300190};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300191static struct v4l2_pix_format sif_mode[] = {
192 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
193 .bytesperline = 176,
194 .sizeimage = 176 * 144,
195 .colorspace = V4L2_COLORSPACE_SRGB,
196 .priv = 1},
197 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
198 .bytesperline = 352,
199 .sizeimage = 352 * 288,
200 .colorspace = V4L2_COLORSPACE_SRGB,
201 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300202};
203
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300204static const __u8 initHv7131[] = {
205 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
206 0x00, 0x00,
207 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
208 0x28, 0x1e, 0x60, 0x8a, 0x20,
209 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
210};
211static const __u8 hv7131_sensor_init[][8] = {
212 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
213 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
214 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
215 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
216 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
217};
218static const __u8 initOv6650[] = {
219 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
220 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
222 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
223};
224static const __u8 ov6650_sensor_init[][8] =
225{
226 /* Bright, contrast, etc are set througth SCBB interface.
227 * AVCAP on win2 do not send any data on this controls. */
228 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300229
230 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300231 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300232 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300233 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300234 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300235 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
236/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
237 * THIS SET GREEN SCREEN
238 * (pixels could be innverted in decode kind of "brg",
239 * but blue wont be there. Avoid this data ... */
240 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
241 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
242 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goede722103e2008-07-17 10:24:47 -0300243 /* Enable rgb brightness control */
244 {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
245 /* HDG: Note windows uses the line below, which sets both register 0x60
246 and 0x61 I believe these registers of the ov6650 are identical as
247 those of the ov7630, because if this is true the windows settings
248 add a bit additional red gain and a lot additional blue gain, which
249 matches my findings that the windows settings make blue much too
250 blue and red a little too red.
251 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
Hans de Goededcef3232008-07-10 10:40:53 -0300252 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300253 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
254 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300255};
Hans de Goededcef3232008-07-10 10:40:53 -0300256
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300257static const __u8 initOv7630[] = {
258 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
259 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
260 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
261 0x28, 0x1e, /* H & V sizes r15 .. r16 */
262 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
263 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
264};
265static const __u8 initOv7630_3[] = {
266 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
267 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300268 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300269 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300270 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
271 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
272 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
273 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300274};
Hans de Goede6af492e2008-07-22 07:09:33 -0300275static const __u8 ov7630_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300276 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
277 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
278/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300279 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300280 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
281 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
282 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
283 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
284 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
285 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
286 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
Andoni Zubimendi794af522008-07-16 08:33:14 -0300287 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
288/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300289 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
290 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
291 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
292 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
293 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
294 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
295};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300296
297static const __u8 initPas106[] = {
298 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
299 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
301 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
302 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
303};
304/* compression 0x86 mckinit1 0x2b */
305static const __u8 pas106_data[][2] = {
306 {0x02, 0x04}, /* Pixel Clock Divider 6 */
307 {0x03, 0x13}, /* Frame Time MSB */
308/* {0x03, 0x12}, * Frame Time MSB */
309 {0x04, 0x06}, /* Frame Time LSB */
310/* {0x04, 0x05}, * Frame Time LSB */
311 {0x05, 0x65}, /* Shutter Time Line Offset */
312/* {0x05, 0x6d}, * Shutter Time Line Offset */
313/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
314 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
315 {0x07, 0xc1}, /* Black Level Subtract Sign */
316/* {0x07, 0x00}, * Black Level Subtract Sign */
317 {0x08, 0x06}, /* Black Level Subtract Level */
318 {0x08, 0x06}, /* Black Level Subtract Level */
319/* {0x08, 0x01}, * Black Level Subtract Level */
320 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
321 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
322 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
323 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
324 {0x0d, 0x00}, /* Color GainH Pixel */
325 {0x0e, 0x0e}, /* Global Gain */
326 {0x0f, 0x00}, /* Contrast */
327 {0x10, 0x06}, /* H&V synchro polarity */
328 {0x11, 0x06}, /* ?default */
329 {0x12, 0x06}, /* DAC scale */
330 {0x14, 0x02}, /* ?default */
331 {0x13, 0x01}, /* Validate Settings */
332};
333static const __u8 initPas202[] = {
334 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
335 0x00, 0x00,
336 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
337 0x28, 0x1e, 0x28, 0x89, 0x30,
338 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
339};
340static const __u8 pas202_sensor_init[][8] = {
341 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
342 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
343 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
344 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
345 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
346 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
347 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
348 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
349 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
350 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
351 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
352 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
353
354 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
355 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
356 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
357 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
358 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
359 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
360 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
361 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
362};
363
364static const __u8 initTas5110[] = {
365 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
366 0x00, 0x00,
367 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
368 0x16, 0x12, 0x60, 0x86, 0x2b,
369 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
370};
371static const __u8 tas5110_sensor_init[][8] = {
372 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
373 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
374 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
375};
376
377static const __u8 initTas5130[] = {
378 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
379 0x00, 0x00,
380 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
381 0x28, 0x1e, 0x60, COMP, MCK_INIT,
382 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
383};
384static const __u8 tas5130_sensor_init[][8] = {
385/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
386 * shutter 0x47 short exposure? */
387 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
388 /* shutter 0x01 long exposure */
389 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
390};
391
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300392/* get one byte in gspca_dev->usb_buf */
393static void reg_r(struct gspca_dev *gspca_dev,
394 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300395{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300396 usb_control_msg(gspca_dev->dev,
397 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300398 0, /* request */
399 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
400 value,
401 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300402 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300403 500);
404}
405
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300406static void reg_w(struct gspca_dev *gspca_dev,
407 __u16 value,
408 const __u8 *buffer,
409 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300410{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300411#ifdef CONFIG_VIDEO_ADV_DEBUG
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300412 if (len > sizeof gspca_dev->usb_buf) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300413 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
414 return;
415 }
416#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300417 memcpy(gspca_dev->usb_buf, buffer, len);
418 usb_control_msg(gspca_dev->dev,
419 usb_sndctrlpipe(gspca_dev->dev, 0),
420 0x08, /* request */
421 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
422 value,
423 0, /* index */
424 gspca_dev->usb_buf, len,
425 500);
426}
427
428static void reg_w_big(struct gspca_dev *gspca_dev,
429 __u16 value,
430 const __u8 *buffer,
431 int len)
432{
433 __u8 *tmpbuf;
434
435 tmpbuf = kmalloc(len, GFP_KERNEL);
Hans de Goede0d2a7222008-07-03 08:15:22 -0300436 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300437 usb_control_msg(gspca_dev->dev,
438 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300439 0x08, /* request */
440 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
441 value,
442 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300443 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300444 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300445 kfree(tmpbuf);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300446}
447
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300448static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300449{
450 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300451
452 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300453 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300454 while (retry--) {
455 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300456 reg_r(gspca_dev, 0x08);
Andoni Zubimendib7474cf2008-07-16 08:40:30 -0300457 if (gspca_dev->usb_buf[0] & 0x04) {
458 if (gspca_dev->usb_buf[0] & 0x08)
459 return -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300460 return 0;
Andoni Zubimendib7474cf2008-07-16 08:40:30 -0300461 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300462 }
463 return -1;
464}
465
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300466static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300467 const __u8 buffer[][8], int len)
468{
469 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300470 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300471 len -= 8;
472 if (len <= 0)
473 break;
474 buffer++;
475 }
476}
477
478static void setbrightness(struct gspca_dev *gspca_dev)
479{
480 struct sd *sd = (struct sd *) gspca_dev;
481 __u8 value;
482
483 switch (sd->sensor) {
Hans de Goedea975a522008-07-16 15:29:11 -0300484 case SENSOR_OV6650:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300485 case SENSOR_OV7630: {
486 __u8 i2cOV[] =
Hans de Goedea975a522008-07-16 15:29:11 -0300487 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300488
489 /* change reg 0x06 */
Hans de Goedea975a522008-07-16 15:29:11 -0300490 i2cOV[1] = sd->sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300491 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300492 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300493 goto err;
494 break;
495 }
496 case SENSOR_PAS106: {
497 __u8 i2c1[] =
498 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
499
500 i2c1[3] = sd->brightness >> 3;
501 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300502 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503 goto err;
504 i2c1[3] = 0x01;
505 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300506 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300507 goto err;
508 break;
509 }
510 case SENSOR_PAS202: {
511 /* __u8 i2cpexpo1[] =
512 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
513 __u8 i2cpexpo[] =
514 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
515 __u8 i2cp202[] =
516 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
517 static __u8 i2cpdoit[] =
518 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
519
520 /* change reg 0x10 */
521 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300522/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300523 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300524/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300525 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300526 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300527 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300528 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300529 goto err;
530 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300531 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300533 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300534 goto err;
535 break;
536 }
Hans de Goededcef3232008-07-10 10:40:53 -0300537 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300538 __u8 i2c[] =
539 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
540
541 value = 0xff - sd->brightness;
542 i2c[4] = value;
543 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300544 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300545 goto err;
546 break;
547 }
Hans de Goededcef3232008-07-10 10:40:53 -0300548 case SENSOR_TAS5110:
549 /* FIXME figure out howto control brightness on TAS5110 */
550 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300551 }
552 return;
553err:
554 PDEBUG(D_ERR, "i2c error brightness");
555}
Hans de Goededcef3232008-07-10 10:40:53 -0300556
557static void setsensorgain(struct gspca_dev *gspca_dev)
558{
559 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea975a522008-07-16 15:29:11 -0300560 unsigned char gain = sd->gain;
Hans de Goededcef3232008-07-10 10:40:53 -0300561
562 switch (sd->sensor) {
563
564 case SENSOR_TAS5110: {
565 __u8 i2c[] =
566 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
567
Hans de Goedea975a522008-07-16 15:29:11 -0300568 i2c[4] = 255 - gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300569 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300570 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300571 break;
572 }
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300573
Hans de Goedea975a522008-07-16 15:29:11 -0300574 case SENSOR_OV6650:
575 gain >>= 1;
576 /* fall thru */
Hans de Goede6af492e2008-07-22 07:09:33 -0300577 case SENSOR_OV7630: {
Hans de Goedea975a522008-07-16 15:29:11 -0300578 __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Andoni Zubimendi794af522008-07-16 08:33:14 -0300579
Hans de Goedea975a522008-07-16 15:29:11 -0300580 i2c[1] = sd->sensor_addr;
581 i2c[3] = gain >> 2;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300582 if (i2c_w(gspca_dev, i2c) < 0)
583 goto err;
584 break;
585 }
Hans de Goededcef3232008-07-10 10:40:53 -0300586 }
587 return;
588err:
589 PDEBUG(D_ERR, "i2c error gain");
590}
591
592static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593{
594 struct sd *sd = (struct sd *) gspca_dev;
595 __u8 gain;
596 __u8 rgb_value;
597
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300598 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300599
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300600 /* red and blue gain */
601 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300602 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300603 /* green gain */
604 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300605 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300606
607 if (sd->sensor_has_gain)
608 setsensorgain(gspca_dev);
609}
610
611static void setexposure(struct gspca_dev *gspca_dev)
612{
613 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300614
615 switch (sd->sensor) {
616 case SENSOR_TAS5110: {
617 __u8 reg;
618
619 /* register 19's high nibble contains the sn9c10x clock divider
620 The high nibble configures the no fps according to the
621 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300622 reg = 120 * sd->exposure / 1000;
623 if (reg < 2)
624 reg = 2;
625 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300626 reg = 15;
627 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300628 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300629 break;
630 }
Hans de Goedea975a522008-07-16 15:29:11 -0300631 case SENSOR_OV6650:
Hans de Goede6af492e2008-07-22 07:09:33 -0300632 case SENSOR_OV7630: {
Hans de Goedea975a522008-07-16 15:29:11 -0300633 /* The ov6650 / ov7630 have 2 registers which both influence
634 exposure, register 11, whose low nibble sets the nr off fps
Hans de Goedef4d52022008-07-15 09:36:42 -0300635 according to: fps = 30 / (low_nibble + 1)
636
637 The fps configures the maximum exposure setting, but it is
638 possible to use less exposure then what the fps maximum
639 allows by setting register 10. register 10 configures the
640 actual exposure as quotient of the full exposure, with 0
641 being no exposure at all (not very usefull) and reg10_max
642 being max exposure possible at that framerate.
643
644 The code maps our 0 - 510 ms exposure ctrl to these 2
645 registers, trying to keep fps as high as possible.
646 */
Hans de Goede6af492e2008-07-22 07:09:33 -0300647 __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10};
648 int reg10, reg11, reg10_max;
649
Hans de Goede66f35822008-07-16 10:16:28 -0300650 /* ov6645 datasheet says reg10_max is 9a, but that uses
651 tline * 2 * reg10 as formula for calculating texpo, the
652 ov6650 probably uses the same formula as the 7730 which uses
653 tline * 4 * reg10, which explains why the reg10max we've
654 found experimentally for the ov6650 is exactly half that of
Hans de Goedea975a522008-07-16 15:29:11 -0300655 the ov6645. The ov7630 datasheet says the max is 0x41. */
Hans de Goede6af492e2008-07-22 07:09:33 -0300656 if (sd->sensor == SENSOR_OV6650) {
657 reg10_max = 0x4d;
658 i2c[4] = 0xc0; /* OV6650 needs non default vsync pol */
659 } else
660 reg10_max = 0x41;
Hans de Goedef4d52022008-07-15 09:36:42 -0300661
662 reg11 = (60 * sd->exposure + 999) / 1000;
663 if (reg11 < 1)
664 reg11 = 1;
665 else if (reg11 > 16)
666 reg11 = 16;
667
668 /* frame exposure time in ms = 1000 * reg11 / 30 ->
669 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
670 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
Hans de Goedea975a522008-07-16 15:29:11 -0300671
672 /* Don't allow this to get below 10 when using autogain, the
673 steps become very large (relatively) when below 10 causing
674 the image to oscilate from much too dark, to much too bright
675 and back again. */
676 if (sd->autogain && reg10 < 10)
677 reg10 = 10;
Hans de Goedef4d52022008-07-15 09:36:42 -0300678 else if (reg10 > reg10_max)
679 reg10 = reg10_max;
680
Hans de Goede6af492e2008-07-22 07:09:33 -0300681 /* In 640x480, if the reg11 has less than 3, the image is
682 unstable (not enough bandwidth). */
683 if (gspca_dev->width == 640 && reg11 < 3)
684 reg11 = 3;
685
Hans de Goedef4d52022008-07-15 09:36:42 -0300686 /* Write reg 10 and reg11 low nibble */
Hans de Goedea975a522008-07-16 15:29:11 -0300687 i2c[1] = sd->sensor_addr;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300688 i2c[3] = reg10;
689 i2c[4] |= reg11 - 1;
Hans de Goede6af492e2008-07-22 07:09:33 -0300690
691 /* If register 11 didn't change, don't change it */
692 if (sd->reg11 == reg11 )
693 i2c[0] = 0xa0;
694
695 if (i2c_w(gspca_dev, i2c) == 0)
696 sd->reg11 = reg11;
697 else
Andoni Zubimendi794af522008-07-16 08:33:14 -0300698 PDEBUG(D_ERR, "i2c error exposure");
699 break;
700 }
Hans de Goededcef3232008-07-10 10:40:53 -0300701 }
702}
703
Hans de Goede66f35822008-07-16 10:16:28 -0300704static void setfreq(struct gspca_dev *gspca_dev)
705{
706 struct sd *sd = (struct sd *) gspca_dev;
707
708 switch (sd->sensor) {
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300709 case SENSOR_OV6650:
Hans de Goede6af492e2008-07-22 07:09:33 -0300710 case SENSOR_OV7630: {
Hans de Goede66f35822008-07-16 10:16:28 -0300711 /* Framerate adjust register for artificial light 50 hz flicker
Hans de Goede6af492e2008-07-22 07:09:33 -0300712 compensation, for the ov6650 this is identical to ov6630
713 0x2b register, see ov6630 datasheet.
714 0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300715 __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goede66f35822008-07-16 10:16:28 -0300716 switch (sd->freq) {
717 default:
718/* case 0: * no filter*/
719/* case 2: * 60 hz */
720 i2c[3] = 0;
721 break;
722 case 1: /* 50 hz */
Hans de Goede722103e2008-07-17 10:24:47 -0300723 i2c[3] = (sd->sensor == SENSOR_OV6650)
724 ? 0x4f : 0x8a;
Hans de Goede66f35822008-07-16 10:16:28 -0300725 break;
726 }
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300727 i2c[1] = sd->sensor_addr;
Hans de Goede66f35822008-07-16 10:16:28 -0300728 if (i2c_w(gspca_dev, i2c) < 0)
729 PDEBUG(D_ERR, "i2c error setfreq");
730 break;
731 }
732 }
733}
734
Hans de Goededcef3232008-07-10 10:40:53 -0300735static void do_autogain(struct gspca_dev *gspca_dev)
736{
737 struct sd *sd = (struct sd *) gspca_dev;
738 int avg_lum = atomic_read(&sd->avg_lum);
739
740 if (avg_lum == -1)
741 return;
742
743 if (sd->autogain_ignore_frames > 0)
744 sd->autogain_ignore_frames--;
745 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
746 sd->brightness * DESIRED_AVG_LUM / 127,
Hans de Goedea975a522008-07-16 15:29:11 -0300747 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
748 PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
749 (int)sd->gain, (int)sd->exposure);
Hans de Goededcef3232008-07-10 10:40:53 -0300750 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Hans de Goedea975a522008-07-16 15:29:11 -0300751 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300752}
753
754/* this function is called at probe time */
755static int sd_config(struct gspca_dev *gspca_dev,
756 const struct usb_device_id *id)
757{
758 struct sd *sd = (struct sd *) gspca_dev;
759 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300760 int sif = 0;
761
Hans de Goededcef3232008-07-10 10:40:53 -0300762 /* nctrls depends upon the sensor, so we use a per cam copy */
763 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
764 gspca_dev->sd_desc = &sd->sd_desc;
765
Jean-Francois Moine5da162e2008-07-26 14:17:23 -0300766 /* copy the webcam info from the device id */
767 sd->sensor = (id->driver_info >> 24) & 0xff;
768 if (id->driver_info & (F_GAIN << 16))
769 sd->sensor_has_gain = 1;
770 if (id->driver_info & (F_AUTO << 16))
771 sd->sd_desc.dq_callback = do_autogain;
772 if (id->driver_info & (F_SIF << 16))
773 sif = 1;
774 if (id->driver_info & (F_H18 << 16))
775 sd->fr_h_sz = 18; /* size of frame header */
776 else
777 sd->fr_h_sz = 12;
778 sd->sd_desc.nctrls = (id->driver_info >> 8) & 0xff;
779 sd->sensor_addr = id->driver_info & 0xff;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300780
781 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300782 cam->epaddr = 0x01;
783 if (!sif) {
784 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300785 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300786 } else {
787 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300788 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300789 }
Hans de Goededcef3232008-07-10 10:40:53 -0300790 sd->brightness = BRIGHTNESS_DEF;
791 sd->gain = GAIN_DEF;
792 sd->exposure = EXPOSURE_DEF;
Hans de Goede6af492e2008-07-22 07:09:33 -0300793 sd->autogain = AUTOGAIN_DEF;
Hans de Goede12ff9122008-07-17 10:30:56 -0300794 sd->freq = FREQ_DEF;
Hans de Goede6af492e2008-07-22 07:09:33 -0300795
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300796 return 0;
797}
798
799/* this function is called at open time */
800static int sd_open(struct gspca_dev *gspca_dev)
801{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300802 reg_r(gspca_dev, 0x00);
803 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300804 return -ENODEV;
805 return 0;
806}
807
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300808static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300809{
810 int i;
811 const __u8 *data;
812 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
813
814 i = ARRAY_SIZE(pas106_data);
815 data = pas106_data[0];
816 while (--i >= 0) {
817 memcpy(&i2c1[2], data, 2);
818 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300819 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300820 PDEBUG(D_ERR, "i2c error pas106");
821 data += 2;
822 }
823}
824
825/* -- start the camera -- */
826static void sd_start(struct gspca_dev *gspca_dev)
827{
828 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede6af492e2008-07-22 07:09:33 -0300829 int mode, l = 0x1f;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300830 const __u8 *sn9c10x;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300831 __u8 reg17_19[3];
832
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300833 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300834 switch (sd->sensor) {
835 case SENSOR_HV7131R:
836 sn9c10x = initHv7131;
837 reg17_19[0] = 0x60;
838 reg17_19[1] = (mode << 4) | 0x8a;
839 reg17_19[2] = 0x20;
840 break;
841 case SENSOR_OV6650:
842 sn9c10x = initOv6650;
843 reg17_19[0] = 0x68;
844 reg17_19[1] = (mode << 4) | 0x8b;
845 reg17_19[2] = 0x20;
846 break;
847 case SENSOR_OV7630:
Hans de Goede6af492e2008-07-22 07:09:33 -0300848 if (sd->fr_h_sz == 18) { /* SN9C103 */
849 sn9c10x = initOv7630_3;
850 l = sizeof initOv7630_3;
851 } else
852 sn9c10x = initOv7630;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300853 reg17_19[0] = 0x68;
854 reg17_19[1] = (mode << 4) | COMP2;
855 reg17_19[2] = MCK_INIT1;
856 break;
857 case SENSOR_PAS106:
858 sn9c10x = initPas106;
859 reg17_19[0] = 0x24; /* 0x28 */
860 reg17_19[1] = (mode << 4) | COMP1;
861 reg17_19[2] = MCK_INIT1;
862 break;
863 case SENSOR_PAS202:
864 sn9c10x = initPas202;
865 reg17_19[0] = mode ? 0x24 : 0x20;
866 reg17_19[1] = (mode << 4) | 0x89;
867 reg17_19[2] = 0x20;
868 break;
869 case SENSOR_TAS5110:
870 sn9c10x = initTas5110;
871 reg17_19[0] = 0x60;
872 reg17_19[1] = (mode << 4) | 0x86;
873 reg17_19[2] = 0x2b; /* 0xf3; */
874 break;
875 default:
876/* case SENSOR_TAS5130CXX: */
877 sn9c10x = initTas5130;
878 reg17_19[0] = 0x60;
879 reg17_19[1] = (mode << 4) | COMP;
880 reg17_19[2] = mode ? 0x23 : 0x43;
881 break;
882 }
Hans de Goede6af492e2008-07-22 07:09:33 -0300883
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300884 /* reg 0x01 bit 2 video transfert on */
Hans de Goedefff42052008-07-23 07:04:39 -0300885 reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300886 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Hans de Goedefff42052008-07-23 07:04:39 -0300887 reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300888 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300889 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300890 switch (sd->sensor) {
891 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300892 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300893 sizeof hv7131_sensor_init);
894 break;
895 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300896 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300897 sizeof ov6650_sensor_init);
898 break;
899 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300900 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300901 sizeof ov7630_sensor_init);
Hans de Goede6af492e2008-07-22 07:09:33 -0300902 if (sd->fr_h_sz == 18) { /* SN9C103 */
903 const __u8 i2c[] = { 0xa0, 0x21, 0x13, 0x80, 0x00,
904 0x00, 0x00, 0x10 };
905 i2c_w(gspca_dev, i2c);
906 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300907 break;
908 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300909 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300910 break;
911 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300912 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300913 sizeof pas202_sensor_init);
914 break;
915 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300916 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300917 sizeof tas5110_sensor_init);
918 break;
919 default:
920/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300921 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300922 sizeof tas5130_sensor_init);
923 break;
924 }
Hans de Goede3647fea2008-07-15 05:36:30 -0300925 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
926 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300927 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300928 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -0300929 /* H_start */
930 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
931 /* V_START */
932 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300933 /* reset 0x17 SensorClk enable inv Clk 0x60 */
934 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300935 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300936 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -0300937 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300938 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300939 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300940 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300941 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300942 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300943 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300944 msleep(20);
945
Hans de Goede6af492e2008-07-22 07:09:33 -0300946 sd->reg11 = -1;
947
Hans de Goededcef3232008-07-10 10:40:53 -0300948 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300949 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -0300950 setexposure(gspca_dev);
Hans de Goede66f35822008-07-16 10:16:28 -0300951 setfreq(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -0300952
Hans de Goede6af492e2008-07-22 07:09:33 -0300953 sd->frames_to_drop = 0;
Hans de Goededcef3232008-07-10 10:40:53 -0300954 sd->autogain_ignore_frames = 0;
955 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300956}
957
958static void sd_stopN(struct gspca_dev *gspca_dev)
959{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300960 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300961
962 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300963 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300964}
965
966static void sd_stop0(struct gspca_dev *gspca_dev)
967{
968}
969
970static void sd_close(struct gspca_dev *gspca_dev)
971{
972}
973
974static void sd_pkt_scan(struct gspca_dev *gspca_dev,
975 struct gspca_frame *frame, /* target */
976 unsigned char *data, /* isoc packet */
977 int len) /* iso packet length */
978{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300979 int i;
Hans de Goededcef3232008-07-10 10:40:53 -0300980 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300981
Hans de Goedec36260e2008-07-16 09:56:07 -0300982 /* frames start with:
983 * ff ff 00 c4 c4 96 synchro
984 * 00 (unknown)
985 * xx (frame sequence / size / compression)
986 * (xx) (idem - extra byte for sn9c103)
987 * ll mm brightness sum inside auto exposure
988 * ll mm brightness sum outside auto exposure
989 * (xx xx xx xx xx) audio values for snc103
990 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300991 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300992 for (i = 0; i < len - 6; i++) {
993 if (data[0 + i] == 0xff
994 && data[1 + i] == 0xff
995 && data[2 + i] == 0x00
996 && data[3 + i] == 0xc4
997 && data[4 + i] == 0xc4
998 && data[5 + i] == 0x96) { /* start of frame */
Hans de Goede6af492e2008-07-22 07:09:33 -0300999 int lum = -1;
1000 int pkt_type = LAST_PACKET;
1001
Hans de Goedec36260e2008-07-16 09:56:07 -03001002 if (len - i < sd->fr_h_sz) {
Hans de Goedec36260e2008-07-16 09:56:07 -03001003 PDEBUG(D_STREAM, "packet too short to"
1004 " get avg brightness");
1005 } else if (sd->fr_h_sz == 12) {
Hans de Goede6af492e2008-07-22 07:09:33 -03001006 lum = data[i + 8] + (data[i + 9] << 8);
Hans de Goededcef3232008-07-10 10:40:53 -03001007 } else {
Hans de Goede6af492e2008-07-22 07:09:33 -03001008 lum = data[i + 9] +
1009 (data[i + 10] << 8);
Hans de Goededcef3232008-07-10 10:40:53 -03001010 }
Hans de Goede6af492e2008-07-22 07:09:33 -03001011 if (lum == 0) {
1012 lum = -1;
1013 sd->frames_to_drop = 2;
1014 }
1015 atomic_set(&sd->avg_lum, lum);
1016
1017 if (sd->frames_to_drop) {
1018 sd->frames_to_drop--;
1019 pkt_type = DISCARD_PACKET;
1020 }
1021
1022 frame = gspca_frame_add(gspca_dev, pkt_type,
1023 frame, data, 0);
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -03001024 data += i + sd->fr_h_sz;
1025 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001026 gspca_frame_add(gspca_dev, FIRST_PACKET,
1027 frame, data, len);
1028 return;
1029 }
1030 }
1031 }
1032 gspca_frame_add(gspca_dev, INTER_PACKET,
1033 frame, data, len);
1034}
1035
1036static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1037{
1038 struct sd *sd = (struct sd *) gspca_dev;
1039
1040 sd->brightness = val;
1041 if (gspca_dev->streaming)
1042 setbrightness(gspca_dev);
1043 return 0;
1044}
1045
1046static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1047{
1048 struct sd *sd = (struct sd *) gspca_dev;
1049
1050 *val = sd->brightness;
1051 return 0;
1052}
1053
Hans de Goededcef3232008-07-10 10:40:53 -03001054static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001055{
1056 struct sd *sd = (struct sd *) gspca_dev;
1057
Hans de Goededcef3232008-07-10 10:40:53 -03001058 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001059 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001060 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001061 return 0;
1062}
1063
Hans de Goededcef3232008-07-10 10:40:53 -03001064static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001065{
1066 struct sd *sd = (struct sd *) gspca_dev;
1067
Hans de Goededcef3232008-07-10 10:40:53 -03001068 *val = sd->gain;
1069 return 0;
1070}
1071
1072static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1073{
1074 struct sd *sd = (struct sd *) gspca_dev;
1075
1076 sd->exposure = val;
1077 if (gspca_dev->streaming)
1078 setexposure(gspca_dev);
1079 return 0;
1080}
1081
1082static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1083{
1084 struct sd *sd = (struct sd *) gspca_dev;
1085
1086 *val = sd->exposure;
1087 return 0;
1088}
1089
1090static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1091{
1092 struct sd *sd = (struct sd *) gspca_dev;
1093
1094 sd->autogain = val;
1095 /* when switching to autogain set defaults to make sure
1096 we are on a valid point of the autogain gain /
1097 exposure knee graph, and give this change time to
1098 take effect before doing autogain. */
1099 if (sd->autogain) {
1100 sd->exposure = EXPOSURE_DEF;
1101 sd->gain = GAIN_DEF;
1102 if (gspca_dev->streaming) {
1103 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1104 setexposure(gspca_dev);
1105 setgain(gspca_dev);
1106 }
1107 }
1108
1109 return 0;
1110}
1111
1112static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1113{
1114 struct sd *sd = (struct sd *) gspca_dev;
1115
1116 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001117 return 0;
1118}
1119
Hans de Goede66f35822008-07-16 10:16:28 -03001120static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1121{
1122 struct sd *sd = (struct sd *) gspca_dev;
1123
1124 sd->freq = val;
1125 if (gspca_dev->streaming)
1126 setfreq(gspca_dev);
1127 return 0;
1128}
1129
1130static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1131{
1132 struct sd *sd = (struct sd *) gspca_dev;
1133
1134 *val = sd->freq;
1135 return 0;
1136}
1137
1138static int sd_querymenu(struct gspca_dev *gspca_dev,
1139 struct v4l2_querymenu *menu)
1140{
1141 switch (menu->id) {
1142 case V4L2_CID_POWER_LINE_FREQUENCY:
1143 switch (menu->index) {
1144 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1145 strcpy((char *) menu->name, "NoFliker");
1146 return 0;
1147 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1148 strcpy((char *) menu->name, "50 Hz");
1149 return 0;
1150 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1151 strcpy((char *) menu->name, "60 Hz");
1152 return 0;
1153 }
1154 break;
1155 }
1156 return -EINVAL;
1157}
1158
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001159/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001160static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001161 .name = MODULE_NAME,
1162 .ctrls = sd_ctrls,
1163 .nctrls = ARRAY_SIZE(sd_ctrls),
1164 .config = sd_config,
1165 .open = sd_open,
1166 .start = sd_start,
1167 .stopN = sd_stopN,
1168 .stop0 = sd_stop0,
1169 .close = sd_close,
1170 .pkt_scan = sd_pkt_scan,
Hans de Goede66f35822008-07-16 10:16:28 -03001171 .querymenu = sd_querymenu,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001172};
1173
1174/* -- module initialisation -- */
Jean-Francois Moine5da162e2008-07-26 14:17:23 -03001175#define SFCI(sensor, flags, nctrls, i2c_addr) \
1176 .driver_info = (SENSOR_ ## sensor << 24) \
1177 | ((flags) << 16) \
1178 | ((nctrls) << 8) \
1179 | (i2c_addr)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001180static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001181#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine5da162e2008-07-26 14:17:23 -03001182 {USB_DEVICE(0x0c45, 0x6001), /* SN9C102 */
1183 SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)},
1184 {USB_DEVICE(0x0c45, 0x6005), /* SN9C101 */
1185 SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)},
1186 {USB_DEVICE(0x0c45, 0x6007), /* SN9C101 */
1187 SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)},
1188 {USB_DEVICE(0x0c45, 0x6009), /* SN9C101 */
1189 SFCI(PAS106, F_SIF, 2, 0)},
1190 {USB_DEVICE(0x0c45, 0x600d), /* SN9C101 */
1191 SFCI(PAS106, F_SIF, 2, 0)},
Hans de Goede5de39b22008-07-17 10:34:28 -03001192#endif
Jean-Francois Moine5da162e2008-07-26 14:17:23 -03001193 {USB_DEVICE(0x0c45, 0x6011), /* SN9C101 - SN9C101G */
1194 SFCI(OV6650, F_GAIN|F_AUTO|F_SIF, 5, 0x60)},
Hans de Goede5de39b22008-07-17 10:34:28 -03001195#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine5da162e2008-07-26 14:17:23 -03001196 {USB_DEVICE(0x0c45, 0x6019), /* SN9C101 */
Jean-Francois Moinec52e4f52008-07-27 02:56:33 -03001197 SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)},
Jean-Francois Moine5da162e2008-07-26 14:17:23 -03001198 {USB_DEVICE(0x0c45, 0x6024), /* SN9C102 */
1199 SFCI(TAS5130CXX, 0, 2, 0)},
1200 {USB_DEVICE(0x0c45, 0x6025), /* SN9C102 */
1201 SFCI(TAS5130CXX, 0, 2, 0)},
1202 {USB_DEVICE(0x0c45, 0x6028), /* SN9C102 */
1203 SFCI(PAS202, 0, 2, 0)},
1204 {USB_DEVICE(0x0c45, 0x6029), /* SN9C101 */
1205 SFCI(PAS106, F_SIF, 2, 0)},
1206 {USB_DEVICE(0x0c45, 0x602c), /* SN9C102 */
Jean-Francois Moinec52e4f52008-07-27 02:56:33 -03001207 SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)},
Jean-Francois Moine5da162e2008-07-26 14:17:23 -03001208 {USB_DEVICE(0x0c45, 0x602d), /* SN9C102 */
1209 SFCI(HV7131R, 0, 2, 0)},
1210 {USB_DEVICE(0x0c45, 0x602e), /* SN9C102 */
Jean-Francois Moinec52e4f52008-07-27 02:56:33 -03001211 SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)},
Jean-Francois Moine5da162e2008-07-26 14:17:23 -03001212 {USB_DEVICE(0x0c45, 0x60af), /* SN9C103 */
1213 SFCI(PAS202, F_H18, 2, 0)},
1214 {USB_DEVICE(0x0c45, 0x60b0), /* SN9C103 */
Jean-Francois Moinec52e4f52008-07-27 02:56:33 -03001215 SFCI(OV7630, F_GAIN|F_AUTO|F_H18, 5, 0x21)},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001216#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001217 {}
1218};
1219MODULE_DEVICE_TABLE(usb, device_table);
1220
1221/* -- device connect -- */
1222static int sd_probe(struct usb_interface *intf,
1223 const struct usb_device_id *id)
1224{
1225 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1226 THIS_MODULE);
1227}
1228
1229static struct usb_driver sd_driver = {
1230 .name = MODULE_NAME,
1231 .id_table = device_table,
1232 .probe = sd_probe,
1233 .disconnect = gspca_disconnect,
1234};
1235
1236/* -- module insert / remove -- */
1237static int __init sd_mod_init(void)
1238{
1239 if (usb_register(&sd_driver) < 0)
1240 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001241 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001242 return 0;
1243}
1244static void __exit sd_mod_exit(void)
1245{
1246 usb_deregister(&sd_driver);
1247 PDEBUG(D_PROBE, "deregistered");
1248}
1249
1250module_init(sd_mod_init);
1251module_exit(sd_mod_exit);