blob: 93d3654565917ee8e81826f95bf6b49bf624c7f4 [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
61#define COMP2 0x8f
62#define COMP 0xc7 /* 0x87 //0x07 */
63#define COMP1 0xc9 /* 0x89 //0x09 */
64
65#define MCK_INIT 0x63
66#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
67
68#define SYS_CLK 0x04
69
Hans de Goededcef3232008-07-10 10:40:53 -030070/* We calculate the autogain at the end of the transfer of a frame, at this
71 moment a frame with the old settings is being transmitted, and a frame is
72 being captured with the old settings. So if we adjust the autogain we must
73 ignore atleast the 2 next frames for the new settings to come into effect
74 before doing any other adjustments */
75#define AUTOGAIN_IGNORE_FRAMES 3
Hans de Goedead5ef80d2008-07-14 10:11:42 -030076#define AUTOGAIN_DEADZONE 1000
Hans de Goededcef3232008-07-10 10:40:53 -030077#define DESIRED_AVG_LUM 7000
78
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030079/* V4L2 controls supported by the driver */
80static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
81static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goededcef3232008-07-10 10:40:53 -030082static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
83static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
84static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
86static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede66f35822008-07-16 10:16:28 -030088static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
89static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030090
91static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030092 {
93 {
94 .id = V4L2_CID_BRIGHTNESS,
95 .type = V4L2_CTRL_TYPE_INTEGER,
96 .name = "Brightness",
97 .minimum = 0,
98 .maximum = 255,
99 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -0300100#define BRIGHTNESS_DEF 127
101 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300102 },
103 .set = sd_setbrightness,
104 .get = sd_getbrightness,
105 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300106 {
107 {
Hans de Goededcef3232008-07-10 10:40:53 -0300108 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300109 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300110 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300112 .maximum = 255,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300113 .step = 1,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300114#define GAIN_DEF 127
115#define GAIN_KNEE 200
Hans de Goededcef3232008-07-10 10:40:53 -0300116 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300117 },
Hans de Goededcef3232008-07-10 10:40:53 -0300118 .set = sd_setgain,
119 .get = sd_getgain,
120 },
Hans de Goededcef3232008-07-10 10:40:53 -0300121 {
122 {
123 .id = V4L2_CID_EXPOSURE,
124 .type = V4L2_CTRL_TYPE_INTEGER,
125 .name = "Exposure",
Hans de Goedef4d52022008-07-15 09:36:42 -0300126#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
127#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
Hans de Goededcef3232008-07-10 10:40:53 -0300128 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300129 .maximum = 255,
Hans de Goededcef3232008-07-10 10:40:53 -0300130 .step = 1,
131 .default_value = EXPOSURE_DEF,
132 .flags = 0,
133 },
134 .set = sd_setexposure,
135 .get = sd_getexposure,
136 },
Hans de Goededcef3232008-07-10 10:40:53 -0300137 {
138 {
139 .id = V4L2_CID_AUTOGAIN,
140 .type = V4L2_CTRL_TYPE_BOOLEAN,
141 .name = "Automatic Gain (and Exposure)",
142 .minimum = 0,
143 .maximum = 1,
144 .step = 1,
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300145#define AUTOGAIN_DEF 1
146 .default_value = AUTOGAIN_DEF,
Hans de Goededcef3232008-07-10 10:40:53 -0300147 .flags = 0,
148 },
149 .set = sd_setautogain,
150 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300151 },
Hans de Goede66f35822008-07-16 10:16:28 -0300152 {
153 {
154 .id = V4L2_CID_POWER_LINE_FREQUENCY,
155 .type = V4L2_CTRL_TYPE_MENU,
156 .name = "Light frequency filter",
157 .minimum = 0,
158 .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
159 .step = 1,
160#define FREQ_DEF 1
161 .default_value = FREQ_DEF,
162 },
163 .set = sd_setfreq,
164 .get = sd_getfreq,
165 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300166};
167
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300168static struct v4l2_pix_format vga_mode[] = {
169 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
170 .bytesperline = 160,
171 .sizeimage = 160 * 120,
172 .colorspace = V4L2_COLORSPACE_SRGB,
173 .priv = 2},
174 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
175 .bytesperline = 320,
176 .sizeimage = 320 * 240,
177 .colorspace = V4L2_COLORSPACE_SRGB,
178 .priv = 1},
179 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
180 .bytesperline = 640,
181 .sizeimage = 640 * 480,
182 .colorspace = V4L2_COLORSPACE_SRGB,
183 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300184};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300185static struct v4l2_pix_format sif_mode[] = {
186 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
187 .bytesperline = 176,
188 .sizeimage = 176 * 144,
189 .colorspace = V4L2_COLORSPACE_SRGB,
190 .priv = 1},
191 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
192 .bytesperline = 352,
193 .sizeimage = 352 * 288,
194 .colorspace = V4L2_COLORSPACE_SRGB,
195 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300196};
197
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300198static const __u8 initHv7131[] = {
199 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
200 0x00, 0x00,
201 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
202 0x28, 0x1e, 0x60, 0x8a, 0x20,
203 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
204};
205static const __u8 hv7131_sensor_init[][8] = {
206 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
207 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
208 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
209 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
210 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
211};
212static const __u8 initOv6650[] = {
213 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
214 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
216 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
217};
218static const __u8 ov6650_sensor_init[][8] =
219{
220 /* Bright, contrast, etc are set througth SCBB interface.
221 * AVCAP on win2 do not send any data on this controls. */
222 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300223
224 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300225 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300226 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300227 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300228 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300229 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
230/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
231 * THIS SET GREEN SCREEN
232 * (pixels could be innverted in decode kind of "brg",
233 * but blue wont be there. Avoid this data ... */
234 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
235 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
236 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goede722103e2008-07-17 10:24:47 -0300237 /* Enable rgb brightness control */
238 {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
239 /* HDG: Note windows uses the line below, which sets both register 0x60
240 and 0x61 I believe these registers of the ov6650 are identical as
241 those of the ov7630, because if this is true the windows settings
242 add a bit additional red gain and a lot additional blue gain, which
243 matches my findings that the windows settings make blue much too
244 blue and red a little too red.
245 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
Hans de Goededcef3232008-07-10 10:40:53 -0300246 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300247 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
248 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300249};
Hans de Goededcef3232008-07-10 10:40:53 -0300250
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300251static const __u8 initOv7630[] = {
252 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
253 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
254 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
255 0x28, 0x1e, /* H & V sizes r15 .. r16 */
256 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
257 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
258};
259static const __u8 initOv7630_3[] = {
260 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
261 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300262 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300263 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300264 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
265 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
266 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
267 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300268};
Hans de Goede6af492e2008-07-22 07:09:33 -0300269static const __u8 ov7630_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300270 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
271 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
272/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300273 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300274 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
275 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
276 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
277 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
278 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
279 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
280 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
Andoni Zubimendi794af522008-07-16 08:33:14 -0300281 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
282/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300283 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
284 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
285 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
286 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
287 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
288 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
289};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300290
291static const __u8 initPas106[] = {
292 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
293 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
295 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
296 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
297};
298/* compression 0x86 mckinit1 0x2b */
299static const __u8 pas106_data[][2] = {
300 {0x02, 0x04}, /* Pixel Clock Divider 6 */
301 {0x03, 0x13}, /* Frame Time MSB */
302/* {0x03, 0x12}, * Frame Time MSB */
303 {0x04, 0x06}, /* Frame Time LSB */
304/* {0x04, 0x05}, * Frame Time LSB */
305 {0x05, 0x65}, /* Shutter Time Line Offset */
306/* {0x05, 0x6d}, * Shutter Time Line Offset */
307/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
308 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
309 {0x07, 0xc1}, /* Black Level Subtract Sign */
310/* {0x07, 0x00}, * Black Level Subtract Sign */
311 {0x08, 0x06}, /* Black Level Subtract Level */
312 {0x08, 0x06}, /* Black Level Subtract Level */
313/* {0x08, 0x01}, * Black Level Subtract Level */
314 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
315 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
316 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
317 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
318 {0x0d, 0x00}, /* Color GainH Pixel */
319 {0x0e, 0x0e}, /* Global Gain */
320 {0x0f, 0x00}, /* Contrast */
321 {0x10, 0x06}, /* H&V synchro polarity */
322 {0x11, 0x06}, /* ?default */
323 {0x12, 0x06}, /* DAC scale */
324 {0x14, 0x02}, /* ?default */
325 {0x13, 0x01}, /* Validate Settings */
326};
327static const __u8 initPas202[] = {
328 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
329 0x00, 0x00,
330 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
331 0x28, 0x1e, 0x28, 0x89, 0x30,
332 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
333};
334static const __u8 pas202_sensor_init[][8] = {
335 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
336 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
337 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
338 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
339 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
340 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
341 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
342 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
343 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
344 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
345 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
346 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
347
348 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
349 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
350 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
351 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
352 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
353 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
354 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
355 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
356};
357
358static const __u8 initTas5110[] = {
359 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
360 0x00, 0x00,
361 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
362 0x16, 0x12, 0x60, 0x86, 0x2b,
363 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
364};
365static const __u8 tas5110_sensor_init[][8] = {
366 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
367 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
368 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
369};
370
371static const __u8 initTas5130[] = {
372 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
373 0x00, 0x00,
374 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
375 0x28, 0x1e, 0x60, COMP, MCK_INIT,
376 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
377};
378static const __u8 tas5130_sensor_init[][8] = {
379/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
380 * shutter 0x47 short exposure? */
381 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
382 /* shutter 0x01 long exposure */
383 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
384};
385
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300386/* get one byte in gspca_dev->usb_buf */
387static void reg_r(struct gspca_dev *gspca_dev,
388 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300389{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300390 usb_control_msg(gspca_dev->dev,
391 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300392 0, /* request */
393 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
394 value,
395 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300396 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300397 500);
398}
399
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300400static void reg_w(struct gspca_dev *gspca_dev,
401 __u16 value,
402 const __u8 *buffer,
403 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300404{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300405#ifdef CONFIG_VIDEO_ADV_DEBUG
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300406 if (len > sizeof gspca_dev->usb_buf) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300407 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
408 return;
409 }
410#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300411 memcpy(gspca_dev->usb_buf, buffer, len);
412 usb_control_msg(gspca_dev->dev,
413 usb_sndctrlpipe(gspca_dev->dev, 0),
414 0x08, /* request */
415 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
416 value,
417 0, /* index */
418 gspca_dev->usb_buf, len,
419 500);
420}
421
422static void reg_w_big(struct gspca_dev *gspca_dev,
423 __u16 value,
424 const __u8 *buffer,
425 int len)
426{
427 __u8 *tmpbuf;
428
429 tmpbuf = kmalloc(len, GFP_KERNEL);
Hans de Goede0d2a7222008-07-03 08:15:22 -0300430 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300431 usb_control_msg(gspca_dev->dev,
432 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300433 0x08, /* request */
434 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
435 value,
436 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300437 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300438 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300439 kfree(tmpbuf);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300440}
441
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300442static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300443{
444 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300445
446 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300447 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300448 while (retry--) {
449 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300450 reg_r(gspca_dev, 0x08);
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300451 if (gspca_dev->usb_buf[0] & 0x04) {
452 if (gspca_dev->usb_buf[0] & 0x08)
453 return -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300454 return 0;
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300455 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300456 }
457 return -1;
458}
459
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300460static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300461 const __u8 buffer[][8], int len)
462{
463 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300464 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300465 len -= 8;
466 if (len <= 0)
467 break;
468 buffer++;
469 }
470}
471
472static void setbrightness(struct gspca_dev *gspca_dev)
473{
474 struct sd *sd = (struct sd *) gspca_dev;
475 __u8 value;
476
477 switch (sd->sensor) {
Hans de Goedea975a522008-07-16 15:29:11 -0300478 case SENSOR_OV6650:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300479 case SENSOR_OV7630: {
480 __u8 i2cOV[] =
Hans de Goedea975a522008-07-16 15:29:11 -0300481 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300482
483 /* change reg 0x06 */
Hans de Goedea975a522008-07-16 15:29:11 -0300484 i2cOV[1] = sd->sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300485 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300486 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300487 goto err;
488 break;
489 }
490 case SENSOR_PAS106: {
491 __u8 i2c1[] =
492 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
493
494 i2c1[3] = sd->brightness >> 3;
495 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300496 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300497 goto err;
498 i2c1[3] = 0x01;
499 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300500 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300501 goto err;
502 break;
503 }
504 case SENSOR_PAS202: {
505 /* __u8 i2cpexpo1[] =
506 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
507 __u8 i2cpexpo[] =
508 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
509 __u8 i2cp202[] =
510 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
511 static __u8 i2cpdoit[] =
512 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
513
514 /* change reg 0x10 */
515 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300516/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300518/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300519 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300520 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300521 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300522 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300523 goto err;
524 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300525 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300526 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300527 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300528 goto err;
529 break;
530 }
Hans de Goededcef3232008-07-10 10:40:53 -0300531 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532 __u8 i2c[] =
533 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
534
535 value = 0xff - sd->brightness;
536 i2c[4] = value;
537 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300538 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300539 goto err;
540 break;
541 }
Hans de Goededcef3232008-07-10 10:40:53 -0300542 case SENSOR_TAS5110:
543 /* FIXME figure out howto control brightness on TAS5110 */
544 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300545 }
546 return;
547err:
548 PDEBUG(D_ERR, "i2c error brightness");
549}
Hans de Goededcef3232008-07-10 10:40:53 -0300550
551static void setsensorgain(struct gspca_dev *gspca_dev)
552{
553 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea975a522008-07-16 15:29:11 -0300554 unsigned char gain = sd->gain;
Hans de Goededcef3232008-07-10 10:40:53 -0300555
556 switch (sd->sensor) {
557
558 case SENSOR_TAS5110: {
559 __u8 i2c[] =
560 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
561
Hans de Goedea975a522008-07-16 15:29:11 -0300562 i2c[4] = 255 - gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300563 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300564 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300565 break;
566 }
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300567
Hans de Goedea975a522008-07-16 15:29:11 -0300568 case SENSOR_OV6650:
569 gain >>= 1;
570 /* fall thru */
Hans de Goede6af492e2008-07-22 07:09:33 -0300571 case SENSOR_OV7630: {
Hans de Goedea975a522008-07-16 15:29:11 -0300572 __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Andoni Zubimendi794af522008-07-16 08:33:14 -0300573
Hans de Goedea975a522008-07-16 15:29:11 -0300574 i2c[1] = sd->sensor_addr;
575 i2c[3] = gain >> 2;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300576 if (i2c_w(gspca_dev, i2c) < 0)
577 goto err;
578 break;
579 }
Hans de Goededcef3232008-07-10 10:40:53 -0300580 }
581 return;
582err:
583 PDEBUG(D_ERR, "i2c error gain");
584}
585
586static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300587{
588 struct sd *sd = (struct sd *) gspca_dev;
589 __u8 gain;
590 __u8 rgb_value;
591
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300592 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300593
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300594 /* red and blue gain */
595 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300596 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300597 /* green gain */
598 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300599 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300600
601 if (sd->sensor_has_gain)
602 setsensorgain(gspca_dev);
603}
604
605static void setexposure(struct gspca_dev *gspca_dev)
606{
607 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300608
609 switch (sd->sensor) {
610 case SENSOR_TAS5110: {
611 __u8 reg;
612
613 /* register 19's high nibble contains the sn9c10x clock divider
614 The high nibble configures the no fps according to the
615 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300616 reg = 120 * sd->exposure / 1000;
617 if (reg < 2)
618 reg = 2;
619 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300620 reg = 15;
621 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300622 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300623 break;
624 }
Hans de Goedea975a522008-07-16 15:29:11 -0300625 case SENSOR_OV6650:
Hans de Goede6af492e2008-07-22 07:09:33 -0300626 case SENSOR_OV7630: {
Hans de Goedea975a522008-07-16 15:29:11 -0300627 /* The ov6650 / ov7630 have 2 registers which both influence
628 exposure, register 11, whose low nibble sets the nr off fps
Hans de Goedef4d52022008-07-15 09:36:42 -0300629 according to: fps = 30 / (low_nibble + 1)
630
631 The fps configures the maximum exposure setting, but it is
632 possible to use less exposure then what the fps maximum
633 allows by setting register 10. register 10 configures the
634 actual exposure as quotient of the full exposure, with 0
635 being no exposure at all (not very usefull) and reg10_max
636 being max exposure possible at that framerate.
637
638 The code maps our 0 - 510 ms exposure ctrl to these 2
639 registers, trying to keep fps as high as possible.
640 */
Hans de Goede6af492e2008-07-22 07:09:33 -0300641 __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10};
642 int reg10, reg11, reg10_max;
643
Hans de Goede66f35822008-07-16 10:16:28 -0300644 /* ov6645 datasheet says reg10_max is 9a, but that uses
645 tline * 2 * reg10 as formula for calculating texpo, the
646 ov6650 probably uses the same formula as the 7730 which uses
647 tline * 4 * reg10, which explains why the reg10max we've
648 found experimentally for the ov6650 is exactly half that of
Hans de Goedea975a522008-07-16 15:29:11 -0300649 the ov6645. The ov7630 datasheet says the max is 0x41. */
Hans de Goede6af492e2008-07-22 07:09:33 -0300650 if (sd->sensor == SENSOR_OV6650) {
651 reg10_max = 0x4d;
652 i2c[4] = 0xc0; /* OV6650 needs non default vsync pol */
653 } else
654 reg10_max = 0x41;
Hans de Goedef4d52022008-07-15 09:36:42 -0300655
656 reg11 = (60 * sd->exposure + 999) / 1000;
657 if (reg11 < 1)
658 reg11 = 1;
659 else if (reg11 > 16)
660 reg11 = 16;
661
662 /* frame exposure time in ms = 1000 * reg11 / 30 ->
663 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
664 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
Hans de Goedea975a522008-07-16 15:29:11 -0300665
666 /* Don't allow this to get below 10 when using autogain, the
667 steps become very large (relatively) when below 10 causing
668 the image to oscilate from much too dark, to much too bright
669 and back again. */
670 if (sd->autogain && reg10 < 10)
671 reg10 = 10;
Hans de Goedef4d52022008-07-15 09:36:42 -0300672 else if (reg10 > reg10_max)
673 reg10 = reg10_max;
674
Hans de Goede6af492e2008-07-22 07:09:33 -0300675 /* In 640x480, if the reg11 has less than 3, the image is
676 unstable (not enough bandwidth). */
677 if (gspca_dev->width == 640 && reg11 < 3)
678 reg11 = 3;
679
Hans de Goedef4d52022008-07-15 09:36:42 -0300680 /* Write reg 10 and reg11 low nibble */
Hans de Goedea975a522008-07-16 15:29:11 -0300681 i2c[1] = sd->sensor_addr;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300682 i2c[3] = reg10;
683 i2c[4] |= reg11 - 1;
Hans de Goede6af492e2008-07-22 07:09:33 -0300684
685 /* If register 11 didn't change, don't change it */
686 if (sd->reg11 == reg11 )
687 i2c[0] = 0xa0;
688
689 if (i2c_w(gspca_dev, i2c) == 0)
690 sd->reg11 = reg11;
691 else
Andoni Zubimendi794af522008-07-16 08:33:14 -0300692 PDEBUG(D_ERR, "i2c error exposure");
693 break;
694 }
Hans de Goededcef3232008-07-10 10:40:53 -0300695 }
696}
697
Hans de Goede66f35822008-07-16 10:16:28 -0300698static void setfreq(struct gspca_dev *gspca_dev)
699{
700 struct sd *sd = (struct sd *) gspca_dev;
701
702 switch (sd->sensor) {
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300703 case SENSOR_OV6650:
Hans de Goede6af492e2008-07-22 07:09:33 -0300704 case SENSOR_OV7630: {
Hans de Goede66f35822008-07-16 10:16:28 -0300705 /* Framerate adjust register for artificial light 50 hz flicker
Hans de Goede6af492e2008-07-22 07:09:33 -0300706 compensation, for the ov6650 this is identical to ov6630
707 0x2b register, see ov6630 datasheet.
708 0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300709 __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goede66f35822008-07-16 10:16:28 -0300710 switch (sd->freq) {
711 default:
712/* case 0: * no filter*/
713/* case 2: * 60 hz */
714 i2c[3] = 0;
715 break;
716 case 1: /* 50 hz */
Hans de Goede722103e2008-07-17 10:24:47 -0300717 i2c[3] = (sd->sensor == SENSOR_OV6650)
718 ? 0x4f : 0x8a;
Hans de Goede66f35822008-07-16 10:16:28 -0300719 break;
720 }
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300721 i2c[1] = sd->sensor_addr;
Hans de Goede66f35822008-07-16 10:16:28 -0300722 if (i2c_w(gspca_dev, i2c) < 0)
723 PDEBUG(D_ERR, "i2c error setfreq");
724 break;
725 }
726 }
727}
728
Hans de Goededcef3232008-07-10 10:40:53 -0300729static void do_autogain(struct gspca_dev *gspca_dev)
730{
731 struct sd *sd = (struct sd *) gspca_dev;
732 int avg_lum = atomic_read(&sd->avg_lum);
733
734 if (avg_lum == -1)
735 return;
736
737 if (sd->autogain_ignore_frames > 0)
738 sd->autogain_ignore_frames--;
739 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
740 sd->brightness * DESIRED_AVG_LUM / 127,
Hans de Goedea975a522008-07-16 15:29:11 -0300741 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
742 PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
743 (int)sd->gain, (int)sd->exposure);
Hans de Goededcef3232008-07-10 10:40:53 -0300744 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Hans de Goedea975a522008-07-16 15:29:11 -0300745 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300746}
747
748/* this function is called at probe time */
749static int sd_config(struct gspca_dev *gspca_dev,
750 const struct usb_device_id *id)
751{
752 struct sd *sd = (struct sd *) gspca_dev;
753 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300754 __u16 product;
755 int sif = 0;
756
Hans de Goededcef3232008-07-10 10:40:53 -0300757 /* nctrls depends upon the sensor, so we use a per cam copy */
758 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
759 gspca_dev->sd_desc = &sd->sd_desc;
760
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300761 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300762 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300763 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300764/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300765/* case 0x0c45: * Sonix */
766 switch (product) {
767 case 0x6001: /* SN9C102 */
768 case 0x6005: /* SN9C101 */
769 case 0x6007: /* SN9C101 */
770 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300771 sd->sensor_has_gain = 1;
772 sd->sd_desc.nctrls = 4;
773 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300774 sif = 1;
775 break;
776 case 0x6009: /* SN9C101 */
777 case 0x600d: /* SN9C101 */
778 case 0x6029: /* SN9C101 */
779 sd->sensor = SENSOR_PAS106;
780 sif = 1;
781 break;
782 case 0x6011: /* SN9C101 - SN9C101G */
783 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300784 sd->sensor_has_gain = 1;
Hans de Goedea975a522008-07-16 15:29:11 -0300785 sd->sensor_addr = 0x60;
Hans de Goede722103e2008-07-17 10:24:47 -0300786 sd->sd_desc.nctrls = 5;
Hans de Goededcef3232008-07-10 10:40:53 -0300787 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300788 sif = 1;
789 break;
790 case 0x6019: /* SN9C101 */
791 case 0x602c: /* SN9C102 */
792 case 0x602e: /* SN9C102 */
Hans de Goede6af492e2008-07-22 07:09:33 -0300793 case 0x60b0: /* SN9C103 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300794 sd->sensor = SENSOR_OV7630;
Hans de Goedea975a522008-07-16 15:29:11 -0300795 sd->sensor_addr = 0x21;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300796 sd->sensor_has_gain = 1;
Hans de Goede6af492e2008-07-22 07:09:33 -0300797 sd->sd_desc.nctrls = 5;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300798 sd->sd_desc.dq_callback = do_autogain;
Hans de Goede6af492e2008-07-22 07:09:33 -0300799 if (product == 0x60b0)
800 sd->fr_h_sz = 18; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300801 break;
802 case 0x6024: /* SN9C102 */
803 case 0x6025: /* SN9C102 */
804 sd->sensor = SENSOR_TAS5130CXX;
805 break;
806 case 0x6028: /* SN9C102 */
807 sd->sensor = SENSOR_PAS202;
808 break;
809 case 0x602d: /* SN9C102 */
810 sd->sensor = SENSOR_HV7131R;
811 break;
812 case 0x60af: /* SN9C103 */
813 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300814 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300815 break;
816 }
817/* break; */
818/* } */
819
820 cam = &gspca_dev->cam;
821 cam->dev_name = (char *) id->driver_info;
822 cam->epaddr = 0x01;
823 if (!sif) {
824 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300825 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300826 } else {
827 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300828 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300829 }
Hans de Goededcef3232008-07-10 10:40:53 -0300830 sd->brightness = BRIGHTNESS_DEF;
831 sd->gain = GAIN_DEF;
832 sd->exposure = EXPOSURE_DEF;
Hans de Goede6af492e2008-07-22 07:09:33 -0300833 sd->autogain = AUTOGAIN_DEF;
Hans de Goede12ff9122008-07-17 10:30:56 -0300834 sd->freq = FREQ_DEF;
Hans de Goede6af492e2008-07-22 07:09:33 -0300835
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300836 return 0;
837}
838
839/* this function is called at open time */
840static int sd_open(struct gspca_dev *gspca_dev)
841{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300842 reg_r(gspca_dev, 0x00);
843 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300844 return -ENODEV;
845 return 0;
846}
847
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300848static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300849{
850 int i;
851 const __u8 *data;
852 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
853
854 i = ARRAY_SIZE(pas106_data);
855 data = pas106_data[0];
856 while (--i >= 0) {
857 memcpy(&i2c1[2], data, 2);
858 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300859 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300860 PDEBUG(D_ERR, "i2c error pas106");
861 data += 2;
862 }
863}
864
865/* -- start the camera -- */
866static void sd_start(struct gspca_dev *gspca_dev)
867{
868 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede6af492e2008-07-22 07:09:33 -0300869 int mode, l = 0x1f;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300870 const __u8 *sn9c10x;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300871 __u8 reg17_19[3];
872
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300873 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300874 switch (sd->sensor) {
875 case SENSOR_HV7131R:
876 sn9c10x = initHv7131;
877 reg17_19[0] = 0x60;
878 reg17_19[1] = (mode << 4) | 0x8a;
879 reg17_19[2] = 0x20;
880 break;
881 case SENSOR_OV6650:
882 sn9c10x = initOv6650;
883 reg17_19[0] = 0x68;
884 reg17_19[1] = (mode << 4) | 0x8b;
885 reg17_19[2] = 0x20;
886 break;
887 case SENSOR_OV7630:
Hans de Goede6af492e2008-07-22 07:09:33 -0300888 if (sd->fr_h_sz == 18) { /* SN9C103 */
889 sn9c10x = initOv7630_3;
890 l = sizeof initOv7630_3;
891 } else
892 sn9c10x = initOv7630;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300893 reg17_19[0] = 0x68;
894 reg17_19[1] = (mode << 4) | COMP2;
895 reg17_19[2] = MCK_INIT1;
896 break;
897 case SENSOR_PAS106:
898 sn9c10x = initPas106;
899 reg17_19[0] = 0x24; /* 0x28 */
900 reg17_19[1] = (mode << 4) | COMP1;
901 reg17_19[2] = MCK_INIT1;
902 break;
903 case SENSOR_PAS202:
904 sn9c10x = initPas202;
905 reg17_19[0] = mode ? 0x24 : 0x20;
906 reg17_19[1] = (mode << 4) | 0x89;
907 reg17_19[2] = 0x20;
908 break;
909 case SENSOR_TAS5110:
910 sn9c10x = initTas5110;
911 reg17_19[0] = 0x60;
912 reg17_19[1] = (mode << 4) | 0x86;
913 reg17_19[2] = 0x2b; /* 0xf3; */
914 break;
915 default:
916/* case SENSOR_TAS5130CXX: */
917 sn9c10x = initTas5130;
918 reg17_19[0] = 0x60;
919 reg17_19[1] = (mode << 4) | COMP;
920 reg17_19[2] = mode ? 0x23 : 0x43;
921 break;
922 }
Hans de Goede6af492e2008-07-22 07:09:33 -0300923
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300924 /* reg 0x01 bit 2 video transfert on */
Hans de Goedefff42052008-07-23 07:04:39 -0300925 reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300926 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Hans de Goedefff42052008-07-23 07:04:39 -0300927 reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300928 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300929 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300930 switch (sd->sensor) {
931 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300932 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300933 sizeof hv7131_sensor_init);
934 break;
935 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300936 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300937 sizeof ov6650_sensor_init);
938 break;
939 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300940 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300941 sizeof ov7630_sensor_init);
Hans de Goede6af492e2008-07-22 07:09:33 -0300942 if (sd->fr_h_sz == 18) { /* SN9C103 */
943 const __u8 i2c[] = { 0xa0, 0x21, 0x13, 0x80, 0x00,
944 0x00, 0x00, 0x10 };
945 i2c_w(gspca_dev, i2c);
946 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300947 break;
948 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300949 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300950 break;
951 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300952 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300953 sizeof pas202_sensor_init);
954 break;
955 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300956 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300957 sizeof tas5110_sensor_init);
958 break;
959 default:
960/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300961 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300962 sizeof tas5130_sensor_init);
963 break;
964 }
Hans de Goede3647fea2008-07-15 05:36:30 -0300965 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
966 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300967 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300968 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -0300969 /* H_start */
970 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
971 /* V_START */
972 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300973 /* reset 0x17 SensorClk enable inv Clk 0x60 */
974 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300975 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300976 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -0300977 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300978 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300979 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300980 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300981 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300982 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300983 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300984 msleep(20);
985
Hans de Goede6af492e2008-07-22 07:09:33 -0300986 sd->reg11 = -1;
987
Hans de Goededcef3232008-07-10 10:40:53 -0300988 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300989 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -0300990 setexposure(gspca_dev);
Hans de Goede66f35822008-07-16 10:16:28 -0300991 setfreq(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -0300992
Hans de Goede6af492e2008-07-22 07:09:33 -0300993 sd->frames_to_drop = 0;
Hans de Goededcef3232008-07-10 10:40:53 -0300994 sd->autogain_ignore_frames = 0;
995 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300996}
997
998static void sd_stopN(struct gspca_dev *gspca_dev)
999{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -03001000 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001001
1002 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001003 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001004}
1005
1006static void sd_stop0(struct gspca_dev *gspca_dev)
1007{
1008}
1009
1010static void sd_close(struct gspca_dev *gspca_dev)
1011{
1012}
1013
1014static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1015 struct gspca_frame *frame, /* target */
1016 unsigned char *data, /* isoc packet */
1017 int len) /* iso packet length */
1018{
Hans de Goede0d2a7222008-07-03 08:15:22 -03001019 int i;
Hans de Goededcef3232008-07-10 10:40:53 -03001020 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001021
Hans de Goedec36260ee2008-07-16 09:56:07 -03001022 /* frames start with:
1023 * ff ff 00 c4 c4 96 synchro
1024 * 00 (unknown)
1025 * xx (frame sequence / size / compression)
1026 * (xx) (idem - extra byte for sn9c103)
1027 * ll mm brightness sum inside auto exposure
1028 * ll mm brightness sum outside auto exposure
1029 * (xx xx xx xx xx) audio values for snc103
1030 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001031 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -03001032 for (i = 0; i < len - 6; i++) {
1033 if (data[0 + i] == 0xff
1034 && data[1 + i] == 0xff
1035 && data[2 + i] == 0x00
1036 && data[3 + i] == 0xc4
1037 && data[4 + i] == 0xc4
1038 && data[5 + i] == 0x96) { /* start of frame */
Hans de Goede6af492e2008-07-22 07:09:33 -03001039 int lum = -1;
1040 int pkt_type = LAST_PACKET;
1041
Hans de Goedec36260ee2008-07-16 09:56:07 -03001042 if (len - i < sd->fr_h_sz) {
Hans de Goedec36260ee2008-07-16 09:56:07 -03001043 PDEBUG(D_STREAM, "packet too short to"
1044 " get avg brightness");
1045 } else if (sd->fr_h_sz == 12) {
Hans de Goede6af492e2008-07-22 07:09:33 -03001046 lum = data[i + 8] + (data[i + 9] << 8);
Hans de Goededcef3232008-07-10 10:40:53 -03001047 } else {
Hans de Goede6af492e2008-07-22 07:09:33 -03001048 lum = data[i + 9] +
1049 (data[i + 10] << 8);
Hans de Goededcef3232008-07-10 10:40:53 -03001050 }
Hans de Goede6af492e2008-07-22 07:09:33 -03001051 if (lum == 0) {
1052 lum = -1;
1053 sd->frames_to_drop = 2;
1054 }
1055 atomic_set(&sd->avg_lum, lum);
1056
1057 if (sd->frames_to_drop) {
1058 sd->frames_to_drop--;
1059 pkt_type = DISCARD_PACKET;
1060 }
1061
1062 frame = gspca_frame_add(gspca_dev, pkt_type,
1063 frame, data, 0);
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -03001064 data += i + sd->fr_h_sz;
1065 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001066 gspca_frame_add(gspca_dev, FIRST_PACKET,
1067 frame, data, len);
1068 return;
1069 }
1070 }
1071 }
1072 gspca_frame_add(gspca_dev, INTER_PACKET,
1073 frame, data, len);
1074}
1075
1076static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1077{
1078 struct sd *sd = (struct sd *) gspca_dev;
1079
1080 sd->brightness = val;
1081 if (gspca_dev->streaming)
1082 setbrightness(gspca_dev);
1083 return 0;
1084}
1085
1086static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1087{
1088 struct sd *sd = (struct sd *) gspca_dev;
1089
1090 *val = sd->brightness;
1091 return 0;
1092}
1093
Hans de Goededcef3232008-07-10 10:40:53 -03001094static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001095{
1096 struct sd *sd = (struct sd *) gspca_dev;
1097
Hans de Goededcef3232008-07-10 10:40:53 -03001098 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001099 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001100 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001101 return 0;
1102}
1103
Hans de Goededcef3232008-07-10 10:40:53 -03001104static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001105{
1106 struct sd *sd = (struct sd *) gspca_dev;
1107
Hans de Goededcef3232008-07-10 10:40:53 -03001108 *val = sd->gain;
1109 return 0;
1110}
1111
1112static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1113{
1114 struct sd *sd = (struct sd *) gspca_dev;
1115
1116 sd->exposure = val;
1117 if (gspca_dev->streaming)
1118 setexposure(gspca_dev);
1119 return 0;
1120}
1121
1122static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1123{
1124 struct sd *sd = (struct sd *) gspca_dev;
1125
1126 *val = sd->exposure;
1127 return 0;
1128}
1129
1130static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1131{
1132 struct sd *sd = (struct sd *) gspca_dev;
1133
1134 sd->autogain = val;
1135 /* when switching to autogain set defaults to make sure
1136 we are on a valid point of the autogain gain /
1137 exposure knee graph, and give this change time to
1138 take effect before doing autogain. */
1139 if (sd->autogain) {
1140 sd->exposure = EXPOSURE_DEF;
1141 sd->gain = GAIN_DEF;
1142 if (gspca_dev->streaming) {
1143 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1144 setexposure(gspca_dev);
1145 setgain(gspca_dev);
1146 }
1147 }
1148
1149 return 0;
1150}
1151
1152static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1153{
1154 struct sd *sd = (struct sd *) gspca_dev;
1155
1156 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001157 return 0;
1158}
1159
Hans de Goede66f35822008-07-16 10:16:28 -03001160static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1161{
1162 struct sd *sd = (struct sd *) gspca_dev;
1163
1164 sd->freq = val;
1165 if (gspca_dev->streaming)
1166 setfreq(gspca_dev);
1167 return 0;
1168}
1169
1170static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1171{
1172 struct sd *sd = (struct sd *) gspca_dev;
1173
1174 *val = sd->freq;
1175 return 0;
1176}
1177
1178static int sd_querymenu(struct gspca_dev *gspca_dev,
1179 struct v4l2_querymenu *menu)
1180{
1181 switch (menu->id) {
1182 case V4L2_CID_POWER_LINE_FREQUENCY:
1183 switch (menu->index) {
1184 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1185 strcpy((char *) menu->name, "NoFliker");
1186 return 0;
1187 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1188 strcpy((char *) menu->name, "50 Hz");
1189 return 0;
1190 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1191 strcpy((char *) menu->name, "60 Hz");
1192 return 0;
1193 }
1194 break;
1195 }
1196 return -EINVAL;
1197}
1198
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001199/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001200static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001201 .name = MODULE_NAME,
1202 .ctrls = sd_ctrls,
1203 .nctrls = ARRAY_SIZE(sd_ctrls),
1204 .config = sd_config,
1205 .open = sd_open,
1206 .start = sd_start,
1207 .stopN = sd_stopN,
1208 .stop0 = sd_stop0,
1209 .close = sd_close,
1210 .pkt_scan = sd_pkt_scan,
Hans de Goede66f35822008-07-16 10:16:28 -03001211 .querymenu = sd_querymenu,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001212};
1213
1214/* -- module initialisation -- */
1215#define DVNM(name) .driver_info = (kernel_ulong_t) name
1216static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001217#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001218 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1219 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1220 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1221 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1222 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Hans de Goede5de39b22008-07-17 10:34:28 -03001223#endif
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001224 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Hans de Goede5de39b22008-07-17 10:34:28 -03001225#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001226 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1227 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1228 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1229 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1230 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1231 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1232 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1233 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1234 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1235 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001236#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001237 {}
1238};
1239MODULE_DEVICE_TABLE(usb, device_table);
1240
1241/* -- device connect -- */
1242static int sd_probe(struct usb_interface *intf,
1243 const struct usb_device_id *id)
1244{
1245 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1246 THIS_MODULE);
1247}
1248
1249static struct usb_driver sd_driver = {
1250 .name = MODULE_NAME,
1251 .id_table = device_table,
1252 .probe = sd_probe,
1253 .disconnect = gspca_disconnect,
1254};
1255
1256/* -- module insert / remove -- */
1257static int __init sd_mod_init(void)
1258{
1259 if (usb_register(&sd_driver) < 0)
1260 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001261 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001262 return 0;
1263}
1264static void __exit sd_mod_exit(void)
1265{
1266 usb_deregister(&sd_driver);
1267 PDEBUG(D_PROBE, "deregistered");
1268}
1269
1270module_init(sd_mod_init);
1271module_exit(sd_mod_exit);