blob: 51435e3dbb1020489b39ac0e3a18bae4912c78fa [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * sonix sn9c102 (bayer) library
3 * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
4 * Add Pas106 Stefano Mozzi (C) 2004
5 *
6 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#define MODULE_NAME "sonixb"
24
25#include "gspca.h"
26
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -030027#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
28static const char version[] = "2.1.7";
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030029
30MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
31MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
32MODULE_LICENSE("GPL");
33
34/* specific webcam descriptor */
35struct sd {
36 struct gspca_dev gspca_dev; /* !! must be the first item */
37
Hans de Goededcef3232008-07-10 10:40:53 -030038 struct sd_desc sd_desc; /* our nctrls differ dependend upon the
39 sensor, so we use a per cam copy */
40 atomic_t avg_lum;
41
Hans de Goedead5ef80d2008-07-14 10:11:42 -030042 unsigned char gain;
43 unsigned char exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030044 unsigned char brightness;
Hans de Goededcef3232008-07-10 10:40:53 -030045 unsigned char autogain;
46 unsigned char autogain_ignore_frames;
Hans de Goede66f35822008-07-16 10:16:28 -030047 unsigned char freq; /* light freq filter setting */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030048
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -030049 unsigned char fr_h_sz; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030050 char sensor; /* Type of image sensor chip */
Hans de Goededcef3232008-07-10 10:40:53 -030051 char sensor_has_gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030052#define SENSOR_HV7131R 0
53#define SENSOR_OV6650 1
54#define SENSOR_OV7630 2
55#define SENSOR_OV7630_3 3
56#define SENSOR_PAS106 4
57#define SENSOR_PAS202 5
58#define SENSOR_TAS5110 6
59#define SENSOR_TAS5130CXX 7
60};
61
62#define COMP2 0x8f
63#define COMP 0xc7 /* 0x87 //0x07 */
64#define COMP1 0xc9 /* 0x89 //0x09 */
65
66#define MCK_INIT 0x63
67#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
68
69#define SYS_CLK 0x04
70
Hans de Goededcef3232008-07-10 10:40:53 -030071/* We calculate the autogain at the end of the transfer of a frame, at this
72 moment a frame with the old settings is being transmitted, and a frame is
73 being captured with the old settings. So if we adjust the autogain we must
74 ignore atleast the 2 next frames for the new settings to come into effect
75 before doing any other adjustments */
76#define AUTOGAIN_IGNORE_FRAMES 3
Hans de Goedead5ef80d2008-07-14 10:11:42 -030077#define AUTOGAIN_DEADZONE 1000
Hans de Goededcef3232008-07-10 10:40:53 -030078#define DESIRED_AVG_LUM 7000
79
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030080/* V4L2 controls supported by the driver */
81static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
82static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goededcef3232008-07-10 10:40:53 -030083static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
84static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
85static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
86static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
87static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
88static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede66f35822008-07-16 10:16:28 -030089static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
90static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030091
92static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030093 {
94 {
95 .id = V4L2_CID_BRIGHTNESS,
96 .type = V4L2_CTRL_TYPE_INTEGER,
97 .name = "Brightness",
98 .minimum = 0,
99 .maximum = 255,
100 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -0300101#define BRIGHTNESS_DEF 127
102 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300103 },
104 .set = sd_setbrightness,
105 .get = sd_getbrightness,
106 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300107 {
108 {
Hans de Goededcef3232008-07-10 10:40:53 -0300109 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300110 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300111 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300112 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300113 .maximum = 255,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300114 .step = 1,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300115#define GAIN_DEF 127
116#define GAIN_KNEE 200
Hans de Goededcef3232008-07-10 10:40:53 -0300117 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300118 },
Hans de Goededcef3232008-07-10 10:40:53 -0300119 .set = sd_setgain,
120 .get = sd_getgain,
121 },
Hans de Goededcef3232008-07-10 10:40:53 -0300122 {
123 {
124 .id = V4L2_CID_EXPOSURE,
125 .type = V4L2_CTRL_TYPE_INTEGER,
126 .name = "Exposure",
Hans de Goedef4d52022008-07-15 09:36:42 -0300127#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
128#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
Hans de Goededcef3232008-07-10 10:40:53 -0300129 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300130 .maximum = 255,
Hans de Goededcef3232008-07-10 10:40:53 -0300131 .step = 1,
132 .default_value = EXPOSURE_DEF,
133 .flags = 0,
134 },
135 .set = sd_setexposure,
136 .get = sd_getexposure,
137 },
Hans de Goededcef3232008-07-10 10:40:53 -0300138 {
139 {
140 .id = V4L2_CID_AUTOGAIN,
141 .type = V4L2_CTRL_TYPE_BOOLEAN,
142 .name = "Automatic Gain (and Exposure)",
143 .minimum = 0,
144 .maximum = 1,
145 .step = 1,
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300146#define AUTOGAIN_DEF 1
147 .default_value = AUTOGAIN_DEF,
Hans de Goededcef3232008-07-10 10:40:53 -0300148 .flags = 0,
149 },
150 .set = sd_setautogain,
151 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300152 },
Hans de Goede66f35822008-07-16 10:16:28 -0300153 {
154 {
155 .id = V4L2_CID_POWER_LINE_FREQUENCY,
156 .type = V4L2_CTRL_TYPE_MENU,
157 .name = "Light frequency filter",
158 .minimum = 0,
159 .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
160 .step = 1,
161#define FREQ_DEF 1
162 .default_value = FREQ_DEF,
163 },
164 .set = sd_setfreq,
165 .get = sd_getfreq,
166 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300167};
168
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300169static struct v4l2_pix_format vga_mode[] = {
170 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
171 .bytesperline = 160,
172 .sizeimage = 160 * 120,
173 .colorspace = V4L2_COLORSPACE_SRGB,
174 .priv = 2},
175 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
176 .bytesperline = 320,
177 .sizeimage = 320 * 240,
178 .colorspace = V4L2_COLORSPACE_SRGB,
179 .priv = 1},
180 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
181 .bytesperline = 640,
182 .sizeimage = 640 * 480,
183 .colorspace = V4L2_COLORSPACE_SRGB,
184 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300185};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300186static struct v4l2_pix_format sif_mode[] = {
187 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
188 .bytesperline = 176,
189 .sizeimage = 176 * 144,
190 .colorspace = V4L2_COLORSPACE_SRGB,
191 .priv = 1},
192 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
193 .bytesperline = 352,
194 .sizeimage = 352 * 288,
195 .colorspace = V4L2_COLORSPACE_SRGB,
196 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300197};
198
199static const __u8 probe_ov7630[] = {0x08, 0x44};
200
201static const __u8 initHv7131[] = {
202 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
203 0x00, 0x00,
204 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
205 0x28, 0x1e, 0x60, 0x8a, 0x20,
206 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
207};
208static const __u8 hv7131_sensor_init[][8] = {
209 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
210 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
211 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
212 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
213 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
214};
215static const __u8 initOv6650[] = {
216 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
217 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
219 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
220};
221static const __u8 ov6650_sensor_init[][8] =
222{
223 /* Bright, contrast, etc are set througth SCBB interface.
224 * AVCAP on win2 do not send any data on this controls. */
225 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300226
227 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300228 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300229 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300230 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300231 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300232 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
233/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
234 * THIS SET GREEN SCREEN
235 * (pixels could be innverted in decode kind of "brg",
236 * but blue wont be there. Avoid this data ... */
237 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
238 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
239 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300240 /* Disable autobright ? */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300241 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300242 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300243 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
244 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300245};
Hans de Goededcef3232008-07-10 10:40:53 -0300246
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300247static const __u8 initOv7630[] = {
248 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
249 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
250 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
251 0x28, 0x1e, /* H & V sizes r15 .. r16 */
252 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
253 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
254};
255static const __u8 initOv7630_3[] = {
256 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
257 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300258 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300259 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300260 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
261 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
262 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
263 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300264};
265static const __u8 ov7630_sensor_init_com[][8] = {
266 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
267 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
268/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300269 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300270 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
271 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
272 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
273 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
274 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
275 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
276 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
Andoni Zubimendi794af522008-07-16 08:33:14 -0300277 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
278/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300279 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
280 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
281 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
282 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
283 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
284 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
285};
286static const __u8 ov7630_sensor_init[][8] = {
287 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
288 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
289 {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
290 {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
291 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
292};
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300293static const __u8 ov7630_sensor_init_3[][5][8] = {
294 { {0xa0, 0x21, 0x10, 0x36, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
295 {0xa0, 0x21, 0x76, 0x03, 0xbd, 0x06, 0xf6, 0x16},
296 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x16},
297 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
298 {0xb0, 0x21, 0x2a, 0xa0, 0x1c, 0x06, 0xf6, 0x1d},
299 },
300 { {0xa0, 0x21, 0x10, 0x83, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300301 {0xa0, 0x21, 0x76, 0x00, 0xbd, 0x06, 0xf6, 0x16},
302 {0xa0, 0x21, 0x11, 0x00, 0xbd, 0x06, 0xf6, 0x16},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300303 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
304/* {0xb0, 0x21, 0x2a, 0xc0, 0x3c, 0x06, 0xf6, 0x1d},
305 * a0 1c,a0 1f,c0 3c frame rate ?line interval from ov6630 */
306/* {0xb0, 0x21, 0x2a, 0xa0, 0x1f, 0x06, 0xf6, 0x1d}, * from win */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300307 {0xb0, 0x21, 0x2a, 0x80, 0x60, 0x06, 0xf6, 0x1d},
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300308 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300309};
310
311static const __u8 initPas106[] = {
312 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
313 0x00, 0x00,
314 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
315 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
316 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
317};
318/* compression 0x86 mckinit1 0x2b */
319static const __u8 pas106_data[][2] = {
320 {0x02, 0x04}, /* Pixel Clock Divider 6 */
321 {0x03, 0x13}, /* Frame Time MSB */
322/* {0x03, 0x12}, * Frame Time MSB */
323 {0x04, 0x06}, /* Frame Time LSB */
324/* {0x04, 0x05}, * Frame Time LSB */
325 {0x05, 0x65}, /* Shutter Time Line Offset */
326/* {0x05, 0x6d}, * Shutter Time Line Offset */
327/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
328 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
329 {0x07, 0xc1}, /* Black Level Subtract Sign */
330/* {0x07, 0x00}, * Black Level Subtract Sign */
331 {0x08, 0x06}, /* Black Level Subtract Level */
332 {0x08, 0x06}, /* Black Level Subtract Level */
333/* {0x08, 0x01}, * Black Level Subtract Level */
334 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
335 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
336 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
337 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
338 {0x0d, 0x00}, /* Color GainH Pixel */
339 {0x0e, 0x0e}, /* Global Gain */
340 {0x0f, 0x00}, /* Contrast */
341 {0x10, 0x06}, /* H&V synchro polarity */
342 {0x11, 0x06}, /* ?default */
343 {0x12, 0x06}, /* DAC scale */
344 {0x14, 0x02}, /* ?default */
345 {0x13, 0x01}, /* Validate Settings */
346};
347static const __u8 initPas202[] = {
348 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
349 0x00, 0x00,
350 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
351 0x28, 0x1e, 0x28, 0x89, 0x30,
352 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
353};
354static const __u8 pas202_sensor_init[][8] = {
355 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
356 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
357 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
358 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
359 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
360 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
361 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
362 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
363 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
364 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
365 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
366 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
367
368 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
369 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
370 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
371 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
372 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
373 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
374 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
375 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
376};
377
378static const __u8 initTas5110[] = {
379 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
380 0x00, 0x00,
381 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
382 0x16, 0x12, 0x60, 0x86, 0x2b,
383 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
384};
385static const __u8 tas5110_sensor_init[][8] = {
386 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
387 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
388 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
389};
390
391static const __u8 initTas5130[] = {
392 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
393 0x00, 0x00,
394 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
395 0x28, 0x1e, 0x60, COMP, MCK_INIT,
396 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
397};
398static const __u8 tas5130_sensor_init[][8] = {
399/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
400 * shutter 0x47 short exposure? */
401 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
402 /* shutter 0x01 long exposure */
403 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
404};
405
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300406/* get one byte in gspca_dev->usb_buf */
407static void reg_r(struct gspca_dev *gspca_dev,
408 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300409{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300410 usb_control_msg(gspca_dev->dev,
411 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300412 0, /* request */
413 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
414 value,
415 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300416 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300417 500);
418}
419
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300420static void reg_w(struct gspca_dev *gspca_dev,
421 __u16 value,
422 const __u8 *buffer,
423 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300424{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300425#ifdef CONFIG_VIDEO_ADV_DEBUG
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300426 if (len > sizeof gspca_dev->usb_buf) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300427 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
428 return;
429 }
430#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300431 memcpy(gspca_dev->usb_buf, buffer, len);
432 usb_control_msg(gspca_dev->dev,
433 usb_sndctrlpipe(gspca_dev->dev, 0),
434 0x08, /* request */
435 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
436 value,
437 0, /* index */
438 gspca_dev->usb_buf, len,
439 500);
440}
441
442static void reg_w_big(struct gspca_dev *gspca_dev,
443 __u16 value,
444 const __u8 *buffer,
445 int len)
446{
447 __u8 *tmpbuf;
448
449 tmpbuf = kmalloc(len, GFP_KERNEL);
Hans de Goede0d2a7222008-07-03 08:15:22 -0300450 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300451 usb_control_msg(gspca_dev->dev,
452 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300453 0x08, /* request */
454 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
455 value,
456 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300457 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300458 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300459 kfree(tmpbuf);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300460}
461
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300462static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300463{
464 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300465
466 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300467 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300468 while (retry--) {
469 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300470 reg_r(gspca_dev, 0x08);
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300471 if (gspca_dev->usb_buf[0] & 0x04) {
472 if (gspca_dev->usb_buf[0] & 0x08)
473 return -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300474 return 0;
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300475 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300476 }
477 return -1;
478}
479
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300480static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300481 const __u8 buffer[][8], int len)
482{
483 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300484 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300485 len -= 8;
486 if (len <= 0)
487 break;
488 buffer++;
489 }
490}
491
492static void setbrightness(struct gspca_dev *gspca_dev)
493{
494 struct sd *sd = (struct sd *) gspca_dev;
495 __u8 value;
496
497 switch (sd->sensor) {
498 case SENSOR_OV6650: {
499 __u8 i2cOV6650[] =
500 {0xa0, 0x60, 0x06, 0x11, 0x99, 0x04, 0x94, 0x15};
501
502 i2cOV6650[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300503 if (i2c_w(gspca_dev, i2cOV6650) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300504 goto err;
505 break;
506 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300507 case SENSOR_OV7630_3:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300508 case SENSOR_OV7630: {
509 __u8 i2cOV[] =
510 {0xa0, 0x21, 0x06, 0x36, 0xbd, 0x06, 0xf6, 0x16};
511
512 /* change reg 0x06 */
513 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300514 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300515 goto err;
516 break;
517 }
518 case SENSOR_PAS106: {
519 __u8 i2c1[] =
520 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
521
522 i2c1[3] = sd->brightness >> 3;
523 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300524 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300525 goto err;
526 i2c1[3] = 0x01;
527 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300528 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300529 goto err;
530 break;
531 }
532 case SENSOR_PAS202: {
533 /* __u8 i2cpexpo1[] =
534 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
535 __u8 i2cpexpo[] =
536 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
537 __u8 i2cp202[] =
538 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
539 static __u8 i2cpdoit[] =
540 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
541
542 /* change reg 0x10 */
543 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300544/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300545 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300546/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300547 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300548 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300549 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300550 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300551 goto err;
552 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300553 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300554 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300555 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300556 goto err;
557 break;
558 }
Hans de Goededcef3232008-07-10 10:40:53 -0300559 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300560 __u8 i2c[] =
561 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
562
563 value = 0xff - sd->brightness;
564 i2c[4] = value;
565 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300566 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300567 goto err;
568 break;
569 }
Hans de Goededcef3232008-07-10 10:40:53 -0300570 case SENSOR_TAS5110:
571 /* FIXME figure out howto control brightness on TAS5110 */
572 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300573 }
574 return;
575err:
576 PDEBUG(D_ERR, "i2c error brightness");
577}
Hans de Goededcef3232008-07-10 10:40:53 -0300578
579static void setsensorgain(struct gspca_dev *gspca_dev)
580{
581 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300582
583 switch (sd->sensor) {
584
585 case SENSOR_TAS5110: {
586 __u8 i2c[] =
587 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
588
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300589 i2c[4] = 255 - sd->gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300590 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300591 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300592 break;
593 }
Hans de Goededcef3232008-07-10 10:40:53 -0300594 case SENSOR_OV6650: {
595 __u8 i2c[] = {0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300596
597 i2c[3] = sd->gain >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300598 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300599 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300600 break;
601 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300602 case SENSOR_OV7630_3: {
603 __u8 i2c[] = {0xa0, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
604
605 i2c[3] = sd->gain >> 2;
606 if (i2c_w(gspca_dev, i2c) < 0)
607 goto err;
608 break;
609 }
Hans de Goededcef3232008-07-10 10:40:53 -0300610 }
611 return;
612err:
613 PDEBUG(D_ERR, "i2c error gain");
614}
615
616static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300617{
618 struct sd *sd = (struct sd *) gspca_dev;
619 __u8 gain;
620 __u8 rgb_value;
621
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300622 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300623
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300624 /* red and blue gain */
625 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300626 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300627 /* green gain */
628 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300629 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300630
631 if (sd->sensor_has_gain)
632 setsensorgain(gspca_dev);
633}
634
635static void setexposure(struct gspca_dev *gspca_dev)
636{
637 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300638
639 switch (sd->sensor) {
640 case SENSOR_TAS5110: {
641 __u8 reg;
642
643 /* register 19's high nibble contains the sn9c10x clock divider
644 The high nibble configures the no fps according to the
645 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300646 reg = 120 * sd->exposure / 1000;
647 if (reg < 2)
648 reg = 2;
649 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300650 reg = 15;
651 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300652 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300653 break;
654 }
Hans de Goededcef3232008-07-10 10:40:53 -0300655 case SENSOR_OV6650: {
Hans de Goedef4d52022008-07-15 09:36:42 -0300656 /* The ov6650 has 2 registers which both influence exposure,
657 first there is register 11, whose low nibble sets the no fps
658 according to: fps = 30 / (low_nibble + 1)
659
660 The fps configures the maximum exposure setting, but it is
661 possible to use less exposure then what the fps maximum
662 allows by setting register 10. register 10 configures the
663 actual exposure as quotient of the full exposure, with 0
664 being no exposure at all (not very usefull) and reg10_max
665 being max exposure possible at that framerate.
666
667 The code maps our 0 - 510 ms exposure ctrl to these 2
668 registers, trying to keep fps as high as possible.
669 */
670 __u8 i2c[] = {0xb0, 0x60, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
671 int reg10, reg11;
Hans de Goede66f35822008-07-16 10:16:28 -0300672 /* ov6645 datasheet says reg10_max is 9a, but that uses
673 tline * 2 * reg10 as formula for calculating texpo, the
674 ov6650 probably uses the same formula as the 7730 which uses
675 tline * 4 * reg10, which explains why the reg10max we've
676 found experimentally for the ov6650 is exactly half that of
677 the ov6645. */
Hans de Goedef4d52022008-07-15 09:36:42 -0300678 const int reg10_max = 0x4d;
679
680 reg11 = (60 * sd->exposure + 999) / 1000;
681 if (reg11 < 1)
682 reg11 = 1;
683 else if (reg11 > 16)
684 reg11 = 16;
685
686 /* frame exposure time in ms = 1000 * reg11 / 30 ->
687 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
688 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
689 if (reg10 < 1) /* 0 is a valid value, but is very _black_ */
690 reg10 = 1;
691 else if (reg10 > reg10_max)
692 reg10 = reg10_max;
693
694 /* Write reg 10 and reg11 low nibble */
695 i2c[3] = reg10;
696 i2c[4] |= reg11 - 1;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300697 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300698 PDEBUG(D_ERR, "i2c error exposure");
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300699 break;
700 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300701 case SENSOR_OV7630_3: {
702 __u8 i2c[] = {0xb0, 0x21, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
703 int reg10, reg11;
704 /* No clear idea why, but setting reg10 above this value
705 results in no change */
706 const int reg10_max = 0x4d;
707
708 reg11 = (60 * sd->exposure + 999) / 1000;
709 if (reg11 < 1)
710 reg11 = 1;
711 else if (reg11 > 16)
712 reg11 = 16;
713
714 /* frame exposure time in ms = 1000 * reg11 / 30 ->
715 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
716 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
717 if (reg10 < 1) /* 0 is a valid value, but is very _black_ */
718 reg10 = 1;
719 else if (reg10 > reg10_max)
720 reg10 = reg10_max;
721
722 /* Write reg 10 and reg11 low nibble */
723 i2c[3] = reg10;
724 i2c[4] |= reg11 - 1;
725 if (i2c_w(gspca_dev, i2c) < 0)
726 PDEBUG(D_ERR, "i2c error exposure");
727 break;
728 }
Hans de Goededcef3232008-07-10 10:40:53 -0300729 }
730}
731
Hans de Goede66f35822008-07-16 10:16:28 -0300732static void setfreq(struct gspca_dev *gspca_dev)
733{
734 struct sd *sd = (struct sd *) gspca_dev;
735
736 switch (sd->sensor) {
737 case SENSOR_OV6650: {
738 /* Framerate adjust register for artificial light 50 hz flicker
739 compensation, identical to ov6630 0x2b register, see ov6630
740 datasheet.
741 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
742 __u8 i2c[] = {0xa0, 0x60, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
743 switch (sd->freq) {
744 default:
745/* case 0: * no filter*/
746/* case 2: * 60 hz */
747 i2c[3] = 0;
748 break;
749 case 1: /* 50 hz */
750 i2c[3] = 0x4f;
751 break;
752 }
753 if (i2c_w(gspca_dev, i2c) < 0)
754 PDEBUG(D_ERR, "i2c error setfreq");
755 break;
756 }
757 }
758}
759
Hans de Goededcef3232008-07-10 10:40:53 -0300760
761static void do_autogain(struct gspca_dev *gspca_dev)
762{
763 struct sd *sd = (struct sd *) gspca_dev;
764 int avg_lum = atomic_read(&sd->avg_lum);
765
766 if (avg_lum == -1)
767 return;
768
769 if (sd->autogain_ignore_frames > 0)
770 sd->autogain_ignore_frames--;
771 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
772 sd->brightness * DESIRED_AVG_LUM / 127,
773 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE))
774 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300775}
776
777/* this function is called at probe time */
778static int sd_config(struct gspca_dev *gspca_dev,
779 const struct usb_device_id *id)
780{
781 struct sd *sd = (struct sd *) gspca_dev;
782 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300783 __u16 product;
784 int sif = 0;
785
Hans de Goededcef3232008-07-10 10:40:53 -0300786 /* nctrls depends upon the sensor, so we use a per cam copy */
787 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
788 gspca_dev->sd_desc = &sd->sd_desc;
789
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300790 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300791 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300792 sd->autogain = AUTOGAIN_DEF; /* default is autogain active */
Hans de Goede66f35822008-07-16 10:16:28 -0300793 sd->freq = FREQ_DEF;
Hans de Goededcef3232008-07-10 10:40:53 -0300794
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300795 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300796/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300797/* case 0x0c45: * Sonix */
798 switch (product) {
799 case 0x6001: /* SN9C102 */
800 case 0x6005: /* SN9C101 */
801 case 0x6007: /* SN9C101 */
802 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300803 sd->sensor_has_gain = 1;
804 sd->sd_desc.nctrls = 4;
805 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300806 sif = 1;
807 break;
808 case 0x6009: /* SN9C101 */
809 case 0x600d: /* SN9C101 */
810 case 0x6029: /* SN9C101 */
811 sd->sensor = SENSOR_PAS106;
812 sif = 1;
813 break;
814 case 0x6011: /* SN9C101 - SN9C101G */
815 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300816 sd->sensor_has_gain = 1;
817 sd->sd_desc.nctrls = 4;
818 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300819 sif = 1;
820 break;
821 case 0x6019: /* SN9C101 */
822 case 0x602c: /* SN9C102 */
823 case 0x602e: /* SN9C102 */
824 sd->sensor = SENSOR_OV7630;
825 break;
826 case 0x60b0: /* SN9C103 */
827 sd->sensor = SENSOR_OV7630_3;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300828 sd->fr_h_sz = 18; /* size of frame header */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300829 sd->sensor_has_gain = 1;
830 sd->sd_desc.nctrls = 4;
831 sd->sd_desc.dq_callback = do_autogain;
832 sd->autogain = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300833 break;
834 case 0x6024: /* SN9C102 */
835 case 0x6025: /* SN9C102 */
836 sd->sensor = SENSOR_TAS5130CXX;
837 break;
838 case 0x6028: /* SN9C102 */
839 sd->sensor = SENSOR_PAS202;
840 break;
841 case 0x602d: /* SN9C102 */
842 sd->sensor = SENSOR_HV7131R;
843 break;
844 case 0x60af: /* SN9C103 */
845 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300846 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300847 break;
848 }
849/* break; */
850/* } */
851
852 cam = &gspca_dev->cam;
853 cam->dev_name = (char *) id->driver_info;
854 cam->epaddr = 0x01;
855 if (!sif) {
856 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300857 cam->nmodes = ARRAY_SIZE(vga_mode);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300858 if (sd->sensor == SENSOR_OV7630_3) {
859 /* We only have 320x240 & 640x480 */
860 cam->cam_mode++;
861 cam->nmodes--;
862 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300863 } else {
864 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300865 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300866 }
Hans de Goededcef3232008-07-10 10:40:53 -0300867 sd->brightness = BRIGHTNESS_DEF;
868 sd->gain = GAIN_DEF;
869 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300870 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300871 reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300872 return 0;
873}
874
875/* this function is called at open time */
876static int sd_open(struct gspca_dev *gspca_dev)
877{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300878 reg_r(gspca_dev, 0x00);
879 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300880 return -ENODEV;
881 return 0;
882}
883
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300884static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300885{
886 int i;
887 const __u8 *data;
888 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
889
890 i = ARRAY_SIZE(pas106_data);
891 data = pas106_data[0];
892 while (--i >= 0) {
893 memcpy(&i2c1[2], data, 2);
894 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300895 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300896 PDEBUG(D_ERR, "i2c error pas106");
897 data += 2;
898 }
899}
900
901/* -- start the camera -- */
902static void sd_start(struct gspca_dev *gspca_dev)
903{
904 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300905 int mode, l;
906 const __u8 *sn9c10x;
907 __u8 reg01, reg17;
908 __u8 reg17_19[3];
909
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300910 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300911 switch (sd->sensor) {
912 case SENSOR_HV7131R:
913 sn9c10x = initHv7131;
914 reg17_19[0] = 0x60;
915 reg17_19[1] = (mode << 4) | 0x8a;
916 reg17_19[2] = 0x20;
917 break;
918 case SENSOR_OV6650:
919 sn9c10x = initOv6650;
920 reg17_19[0] = 0x68;
921 reg17_19[1] = (mode << 4) | 0x8b;
922 reg17_19[2] = 0x20;
923 break;
924 case SENSOR_OV7630:
925 sn9c10x = initOv7630;
926 reg17_19[0] = 0x68;
927 reg17_19[1] = (mode << 4) | COMP2;
928 reg17_19[2] = MCK_INIT1;
929 break;
930 case SENSOR_OV7630_3:
931 sn9c10x = initOv7630_3;
932 reg17_19[0] = 0x68;
933 reg17_19[1] = (mode << 4) | COMP2;
934 reg17_19[2] = MCK_INIT1;
935 break;
936 case SENSOR_PAS106:
937 sn9c10x = initPas106;
938 reg17_19[0] = 0x24; /* 0x28 */
939 reg17_19[1] = (mode << 4) | COMP1;
940 reg17_19[2] = MCK_INIT1;
941 break;
942 case SENSOR_PAS202:
943 sn9c10x = initPas202;
944 reg17_19[0] = mode ? 0x24 : 0x20;
945 reg17_19[1] = (mode << 4) | 0x89;
946 reg17_19[2] = 0x20;
947 break;
948 case SENSOR_TAS5110:
949 sn9c10x = initTas5110;
950 reg17_19[0] = 0x60;
951 reg17_19[1] = (mode << 4) | 0x86;
952 reg17_19[2] = 0x2b; /* 0xf3; */
953 break;
954 default:
955/* case SENSOR_TAS5130CXX: */
956 sn9c10x = initTas5130;
957 reg17_19[0] = 0x60;
958 reg17_19[1] = (mode << 4) | COMP;
959 reg17_19[2] = mode ? 0x23 : 0x43;
960 break;
961 }
962 switch (sd->sensor) {
963 case SENSOR_OV7630:
964 reg01 = 0x06;
965 reg17 = 0x29;
966 l = 0x10;
967 break;
968 case SENSOR_OV7630_3:
969 reg01 = 0x44;
970 reg17 = 0x68;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300971 l = sizeof initOv7630_3;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300972 break;
973 default:
974 reg01 = sn9c10x[0];
975 reg17 = sn9c10x[0x17 - 1];
976 l = 0x1f;
977 break;
978 }
979
980 /* reg 0x01 bit 2 video transfert on */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300981 reg_w(gspca_dev, 0x01, &reg01, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300982 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300983 reg_w(gspca_dev, 0x17, &reg17, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300984/*fixme: for ov7630 102
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300985 reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300986 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300987 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300988 switch (sd->sensor) {
989 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300990 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300991 sizeof hv7131_sensor_init);
992 break;
993 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300994 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300995 sizeof ov6650_sensor_init);
996 break;
997 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300998 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300999 sizeof ov7630_sensor_init_com);
1000 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001001 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001002 sizeof ov7630_sensor_init);
1003 break;
1004 case SENSOR_OV7630_3:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001005 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001006 sizeof ov7630_sensor_init_com);
1007 msleep(200);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -03001008 i2c_w_vector(gspca_dev, ov7630_sensor_init_3[mode],
1009 sizeof ov7630_sensor_init_3[mode]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001010 break;
1011 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001012 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001013 break;
1014 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001015 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001016 sizeof pas202_sensor_init);
1017 break;
1018 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001019 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001020 sizeof tas5110_sensor_init);
1021 break;
1022 default:
1023/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001024 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001025 sizeof tas5130_sensor_init);
1026 break;
1027 }
Hans de Goede3647fea2008-07-15 05:36:30 -03001028 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
1029 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001030 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001031 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -03001032 /* H_start */
1033 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
1034 /* V_START */
1035 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001036 /* reset 0x17 SensorClk enable inv Clk 0x60 */
1037 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001038 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001039 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -03001040 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001041 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001042 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001043 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001044 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001045 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001046 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001047 msleep(20);
1048
Hans de Goededcef3232008-07-10 10:40:53 -03001049 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001050 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001051 setexposure(gspca_dev);
Hans de Goede66f35822008-07-16 10:16:28 -03001052 setfreq(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001053
1054 sd->autogain_ignore_frames = 0;
1055 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001056}
1057
1058static void sd_stopN(struct gspca_dev *gspca_dev)
1059{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -03001060 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001061
1062 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001063 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001064}
1065
1066static void sd_stop0(struct gspca_dev *gspca_dev)
1067{
1068}
1069
1070static void sd_close(struct gspca_dev *gspca_dev)
1071{
1072}
1073
1074static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1075 struct gspca_frame *frame, /* target */
1076 unsigned char *data, /* isoc packet */
1077 int len) /* iso packet length */
1078{
Hans de Goede0d2a7222008-07-03 08:15:22 -03001079 int i;
Hans de Goededcef3232008-07-10 10:40:53 -03001080 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001081
Hans de Goedec36260ee2008-07-16 09:56:07 -03001082 /* frames start with:
1083 * ff ff 00 c4 c4 96 synchro
1084 * 00 (unknown)
1085 * xx (frame sequence / size / compression)
1086 * (xx) (idem - extra byte for sn9c103)
1087 * ll mm brightness sum inside auto exposure
1088 * ll mm brightness sum outside auto exposure
1089 * (xx xx xx xx xx) audio values for snc103
1090 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001091 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -03001092 for (i = 0; i < len - 6; i++) {
1093 if (data[0 + i] == 0xff
1094 && data[1 + i] == 0xff
1095 && data[2 + i] == 0x00
1096 && data[3 + i] == 0xc4
1097 && data[4 + i] == 0xc4
1098 && data[5 + i] == 0x96) { /* start of frame */
1099 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
1100 frame, data, 0);
Hans de Goedec36260ee2008-07-16 09:56:07 -03001101 if (len - i < sd->fr_h_sz) {
1102 atomic_set(&sd->avg_lum, -1);
1103 PDEBUG(D_STREAM, "packet too short to"
1104 " get avg brightness");
1105 } else if (sd->fr_h_sz == 12) {
1106 atomic_set(&sd->avg_lum,
1107 data[i + 8] +
Hans de Goededcef3232008-07-10 10:40:53 -03001108 (data[i + 9] << 8));
1109 } else {
Hans de Goedec36260ee2008-07-16 09:56:07 -03001110 atomic_set(&sd->avg_lum,
1111 data[i + 9] +
1112 (data[i + 10] << 8));
Hans de Goededcef3232008-07-10 10:40:53 -03001113 }
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -03001114 data += i + sd->fr_h_sz;
1115 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001116 gspca_frame_add(gspca_dev, FIRST_PACKET,
1117 frame, data, len);
1118 return;
1119 }
1120 }
1121 }
1122 gspca_frame_add(gspca_dev, INTER_PACKET,
1123 frame, data, len);
1124}
1125
1126static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1127{
1128 struct sd *sd = (struct sd *) gspca_dev;
1129
1130 sd->brightness = val;
1131 if (gspca_dev->streaming)
1132 setbrightness(gspca_dev);
1133 return 0;
1134}
1135
1136static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1137{
1138 struct sd *sd = (struct sd *) gspca_dev;
1139
1140 *val = sd->brightness;
1141 return 0;
1142}
1143
Hans de Goededcef3232008-07-10 10:40:53 -03001144static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001145{
1146 struct sd *sd = (struct sd *) gspca_dev;
1147
Hans de Goededcef3232008-07-10 10:40:53 -03001148 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001149 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001150 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001151 return 0;
1152}
1153
Hans de Goededcef3232008-07-10 10:40:53 -03001154static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001155{
1156 struct sd *sd = (struct sd *) gspca_dev;
1157
Hans de Goededcef3232008-07-10 10:40:53 -03001158 *val = sd->gain;
1159 return 0;
1160}
1161
1162static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1163{
1164 struct sd *sd = (struct sd *) gspca_dev;
1165
1166 sd->exposure = val;
1167 if (gspca_dev->streaming)
1168 setexposure(gspca_dev);
1169 return 0;
1170}
1171
1172static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1173{
1174 struct sd *sd = (struct sd *) gspca_dev;
1175
1176 *val = sd->exposure;
1177 return 0;
1178}
1179
1180static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1181{
1182 struct sd *sd = (struct sd *) gspca_dev;
1183
1184 sd->autogain = val;
1185 /* when switching to autogain set defaults to make sure
1186 we are on a valid point of the autogain gain /
1187 exposure knee graph, and give this change time to
1188 take effect before doing autogain. */
1189 if (sd->autogain) {
1190 sd->exposure = EXPOSURE_DEF;
1191 sd->gain = GAIN_DEF;
1192 if (gspca_dev->streaming) {
1193 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1194 setexposure(gspca_dev);
1195 setgain(gspca_dev);
1196 }
1197 }
1198
1199 return 0;
1200}
1201
1202static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1203{
1204 struct sd *sd = (struct sd *) gspca_dev;
1205
1206 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001207 return 0;
1208}
1209
Hans de Goede66f35822008-07-16 10:16:28 -03001210static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1211{
1212 struct sd *sd = (struct sd *) gspca_dev;
1213
1214 sd->freq = val;
1215 if (gspca_dev->streaming)
1216 setfreq(gspca_dev);
1217 return 0;
1218}
1219
1220static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1221{
1222 struct sd *sd = (struct sd *) gspca_dev;
1223
1224 *val = sd->freq;
1225 return 0;
1226}
1227
1228static int sd_querymenu(struct gspca_dev *gspca_dev,
1229 struct v4l2_querymenu *menu)
1230{
1231 switch (menu->id) {
1232 case V4L2_CID_POWER_LINE_FREQUENCY:
1233 switch (menu->index) {
1234 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1235 strcpy((char *) menu->name, "NoFliker");
1236 return 0;
1237 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1238 strcpy((char *) menu->name, "50 Hz");
1239 return 0;
1240 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1241 strcpy((char *) menu->name, "60 Hz");
1242 return 0;
1243 }
1244 break;
1245 }
1246 return -EINVAL;
1247}
1248
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001249/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001250static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001251 .name = MODULE_NAME,
1252 .ctrls = sd_ctrls,
1253 .nctrls = ARRAY_SIZE(sd_ctrls),
1254 .config = sd_config,
1255 .open = sd_open,
1256 .start = sd_start,
1257 .stopN = sd_stopN,
1258 .stop0 = sd_stop0,
1259 .close = sd_close,
1260 .pkt_scan = sd_pkt_scan,
Hans de Goede66f35822008-07-16 10:16:28 -03001261 .querymenu = sd_querymenu,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001262};
1263
1264/* -- module initialisation -- */
1265#define DVNM(name) .driver_info = (kernel_ulong_t) name
1266static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001267#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001268 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1269 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1270 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1271 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1272 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001273 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001274 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1275 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1276 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1277 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1278 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1279 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1280 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1281 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1282 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1283 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001284#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001285 {}
1286};
1287MODULE_DEVICE_TABLE(usb, device_table);
1288
1289/* -- device connect -- */
1290static int sd_probe(struct usb_interface *intf,
1291 const struct usb_device_id *id)
1292{
1293 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1294 THIS_MODULE);
1295}
1296
1297static struct usb_driver sd_driver = {
1298 .name = MODULE_NAME,
1299 .id_table = device_table,
1300 .probe = sd_probe,
1301 .disconnect = gspca_disconnect,
1302};
1303
1304/* -- module insert / remove -- */
1305static int __init sd_mod_init(void)
1306{
1307 if (usb_register(&sd_driver) < 0)
1308 return -1;
1309 PDEBUG(D_PROBE, "v%s registered", version);
1310 return 0;
1311}
1312static void __exit sd_mod_exit(void)
1313{
1314 usb_deregister(&sd_driver);
1315 PDEBUG(D_PROBE, "deregistered");
1316}
1317
1318module_init(sd_mod_init);
1319module_exit(sd_mod_exit);