blob: 054ce4e3ece7f318c8e668872ab961816babf705 [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;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030047
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -030048 unsigned char fr_h_sz; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030049 char sensor; /* Type of image sensor chip */
Hans de Goededcef3232008-07-10 10:40:53 -030050 char sensor_has_gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030051#define SENSOR_HV7131R 0
52#define SENSOR_OV6650 1
53#define SENSOR_OV7630 2
54#define SENSOR_OV7630_3 3
55#define SENSOR_PAS106 4
56#define SENSOR_PAS202 5
57#define SENSOR_TAS5110 6
58#define SENSOR_TAS5130CXX 7
59};
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);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030088
89static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030090 {
91 {
92 .id = V4L2_CID_BRIGHTNESS,
93 .type = V4L2_CTRL_TYPE_INTEGER,
94 .name = "Brightness",
95 .minimum = 0,
96 .maximum = 255,
97 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -030098#define BRIGHTNESS_DEF 127
99 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300100 },
101 .set = sd_setbrightness,
102 .get = sd_getbrightness,
103 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104 {
105 {
Hans de Goededcef3232008-07-10 10:40:53 -0300106 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300107 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300108 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300109 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300110 .maximum = 255,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 .step = 1,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300112#define GAIN_DEF 127
113#define GAIN_KNEE 200
Hans de Goededcef3232008-07-10 10:40:53 -0300114 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300115 },
Hans de Goededcef3232008-07-10 10:40:53 -0300116 .set = sd_setgain,
117 .get = sd_getgain,
118 },
Hans de Goededcef3232008-07-10 10:40:53 -0300119 {
120 {
121 .id = V4L2_CID_EXPOSURE,
122 .type = V4L2_CTRL_TYPE_INTEGER,
123 .name = "Exposure",
Hans de Goedef4d52022008-07-15 09:36:42 -0300124#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
125#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
Hans de Goededcef3232008-07-10 10:40:53 -0300126 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300127 .maximum = 255,
Hans de Goededcef3232008-07-10 10:40:53 -0300128 .step = 1,
129 .default_value = EXPOSURE_DEF,
130 .flags = 0,
131 },
132 .set = sd_setexposure,
133 .get = sd_getexposure,
134 },
Hans de Goededcef3232008-07-10 10:40:53 -0300135 {
136 {
137 .id = V4L2_CID_AUTOGAIN,
138 .type = V4L2_CTRL_TYPE_BOOLEAN,
139 .name = "Automatic Gain (and Exposure)",
140 .minimum = 0,
141 .maximum = 1,
142 .step = 1,
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300143#define AUTOGAIN_DEF 1
144 .default_value = AUTOGAIN_DEF,
Hans de Goededcef3232008-07-10 10:40:53 -0300145 .flags = 0,
146 },
147 .set = sd_setautogain,
148 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300149 },
150};
151
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300152static struct v4l2_pix_format vga_mode[] = {
153 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
154 .bytesperline = 160,
155 .sizeimage = 160 * 120,
156 .colorspace = V4L2_COLORSPACE_SRGB,
157 .priv = 2},
158 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
159 .bytesperline = 320,
160 .sizeimage = 320 * 240,
161 .colorspace = V4L2_COLORSPACE_SRGB,
162 .priv = 1},
163 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
164 .bytesperline = 640,
165 .sizeimage = 640 * 480,
166 .colorspace = V4L2_COLORSPACE_SRGB,
167 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300168};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300169static struct v4l2_pix_format sif_mode[] = {
170 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
171 .bytesperline = 176,
172 .sizeimage = 176 * 144,
173 .colorspace = V4L2_COLORSPACE_SRGB,
174 .priv = 1},
175 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
176 .bytesperline = 352,
177 .sizeimage = 352 * 288,
178 .colorspace = V4L2_COLORSPACE_SRGB,
179 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300180};
181
182static const __u8 probe_ov7630[] = {0x08, 0x44};
183
184static const __u8 initHv7131[] = {
185 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
186 0x00, 0x00,
187 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
188 0x28, 0x1e, 0x60, 0x8a, 0x20,
189 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
190};
191static const __u8 hv7131_sensor_init[][8] = {
192 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
193 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
194 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
195 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
196 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
197};
198static const __u8 initOv6650[] = {
199 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
200 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
202 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
203};
204static const __u8 ov6650_sensor_init[][8] =
205{
206 /* Bright, contrast, etc are set througth SCBB interface.
207 * AVCAP on win2 do not send any data on this controls. */
208 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300209
210 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300211 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300212 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300213 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300214 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300215 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
216/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
217 * THIS SET GREEN SCREEN
218 * (pixels could be innverted in decode kind of "brg",
219 * but blue wont be there. Avoid this data ... */
220 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
221 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
222 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300223 /* Disable autobright ? */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300224 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300225 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300226 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
227 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300228 {0xa0, 0x60, 0x10, 0x57, 0x99, 0x04, 0x94, 0x16},
Hans de Goededcef3232008-07-10 10:40:53 -0300229 /* Framerate adjust register for artificial light 50 hz flicker
230 compensation, identical to ov6630 0x2b register, see 6630 datasheet.
231 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
232 {0xa0, 0x60, 0x2b, 0x4f, 0x99, 0x04, 0x94, 0x15},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300233};
Hans de Goededcef3232008-07-10 10:40:53 -0300234
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300235static const __u8 initOv7630[] = {
236 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
237 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
238 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
239 0x28, 0x1e, /* H & V sizes r15 .. r16 */
240 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
241 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
242};
243static const __u8 initOv7630_3[] = {
244 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
245 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300246 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300247 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300248 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
249 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
250 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
251 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300252};
253static const __u8 ov7630_sensor_init_com[][8] = {
254 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
255 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
256/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300257 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300258 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
259 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
260 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
261 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
262 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
263 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
264 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
Andoni Zubimendi794af522008-07-16 08:33:14 -0300265 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
266/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300267 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
268 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
269 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
270 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
271 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
272 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
273};
274static const __u8 ov7630_sensor_init[][8] = {
275 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
276 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
277 {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
278 {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
279 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
280};
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300281static const __u8 ov7630_sensor_init_3[][5][8] = {
282 { {0xa0, 0x21, 0x10, 0x36, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
283 {0xa0, 0x21, 0x76, 0x03, 0xbd, 0x06, 0xf6, 0x16},
284 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x16},
285 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
286 {0xb0, 0x21, 0x2a, 0xa0, 0x1c, 0x06, 0xf6, 0x1d},
287 },
288 { {0xa0, 0x21, 0x10, 0x83, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300289 {0xa0, 0x21, 0x76, 0x00, 0xbd, 0x06, 0xf6, 0x16},
290 {0xa0, 0x21, 0x11, 0x00, 0xbd, 0x06, 0xf6, 0x16},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300291 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
292/* {0xb0, 0x21, 0x2a, 0xc0, 0x3c, 0x06, 0xf6, 0x1d},
293 * a0 1c,a0 1f,c0 3c frame rate ?line interval from ov6630 */
294/* {0xb0, 0x21, 0x2a, 0xa0, 0x1f, 0x06, 0xf6, 0x1d}, * from win */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300295 {0xb0, 0x21, 0x2a, 0x80, 0x60, 0x06, 0xf6, 0x1d},
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300296 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300297};
298
299static const __u8 initPas106[] = {
300 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
301 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
303 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
304 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
305};
306/* compression 0x86 mckinit1 0x2b */
307static const __u8 pas106_data[][2] = {
308 {0x02, 0x04}, /* Pixel Clock Divider 6 */
309 {0x03, 0x13}, /* Frame Time MSB */
310/* {0x03, 0x12}, * Frame Time MSB */
311 {0x04, 0x06}, /* Frame Time LSB */
312/* {0x04, 0x05}, * Frame Time LSB */
313 {0x05, 0x65}, /* Shutter Time Line Offset */
314/* {0x05, 0x6d}, * Shutter Time Line Offset */
315/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
316 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
317 {0x07, 0xc1}, /* Black Level Subtract Sign */
318/* {0x07, 0x00}, * Black Level Subtract Sign */
319 {0x08, 0x06}, /* Black Level Subtract Level */
320 {0x08, 0x06}, /* Black Level Subtract Level */
321/* {0x08, 0x01}, * Black Level Subtract Level */
322 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
323 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
324 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
325 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
326 {0x0d, 0x00}, /* Color GainH Pixel */
327 {0x0e, 0x0e}, /* Global Gain */
328 {0x0f, 0x00}, /* Contrast */
329 {0x10, 0x06}, /* H&V synchro polarity */
330 {0x11, 0x06}, /* ?default */
331 {0x12, 0x06}, /* DAC scale */
332 {0x14, 0x02}, /* ?default */
333 {0x13, 0x01}, /* Validate Settings */
334};
335static const __u8 initPas202[] = {
336 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
337 0x00, 0x00,
338 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
339 0x28, 0x1e, 0x28, 0x89, 0x30,
340 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
341};
342static const __u8 pas202_sensor_init[][8] = {
343 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
344 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
345 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
346 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
347 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
348 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
349 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
350 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
351 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
352 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
353 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
354 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
355
356 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
357 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
358 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
359 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
360 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
361 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
362 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
363 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
364};
365
366static const __u8 initTas5110[] = {
367 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
368 0x00, 0x00,
369 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
370 0x16, 0x12, 0x60, 0x86, 0x2b,
371 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
372};
373static const __u8 tas5110_sensor_init[][8] = {
374 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
375 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
376 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
377};
378
379static const __u8 initTas5130[] = {
380 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
381 0x00, 0x00,
382 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
383 0x28, 0x1e, 0x60, COMP, MCK_INIT,
384 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
385};
386static const __u8 tas5130_sensor_init[][8] = {
387/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
388 * shutter 0x47 short exposure? */
389 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
390 /* shutter 0x01 long exposure */
391 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
392};
393
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300394/* get one byte in gspca_dev->usb_buf */
395static void reg_r(struct gspca_dev *gspca_dev,
396 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300397{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300398 usb_control_msg(gspca_dev->dev,
399 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300400 0, /* request */
401 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
402 value,
403 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300404 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405 500);
406}
407
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300408static void reg_w(struct gspca_dev *gspca_dev,
409 __u16 value,
410 const __u8 *buffer,
411 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300412{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300413#ifdef CONFIG_VIDEO_ADV_DEBUG
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300414 if (len > sizeof gspca_dev->usb_buf) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300415 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
416 return;
417 }
418#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300419 memcpy(gspca_dev->usb_buf, buffer, len);
420 usb_control_msg(gspca_dev->dev,
421 usb_sndctrlpipe(gspca_dev->dev, 0),
422 0x08, /* request */
423 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
424 value,
425 0, /* index */
426 gspca_dev->usb_buf, len,
427 500);
428}
429
430static void reg_w_big(struct gspca_dev *gspca_dev,
431 __u16 value,
432 const __u8 *buffer,
433 int len)
434{
435 __u8 *tmpbuf;
436
437 tmpbuf = kmalloc(len, GFP_KERNEL);
Hans de Goede0d2a7222008-07-03 08:15:22 -0300438 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300439 usb_control_msg(gspca_dev->dev,
440 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300441 0x08, /* request */
442 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
443 value,
444 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300445 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300446 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300447 kfree(tmpbuf);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300448}
449
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300450static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300451{
452 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300453
454 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300455 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300456 while (retry--) {
457 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300458 reg_r(gspca_dev, 0x08);
459 if (gspca_dev->usb_buf[0] == 4)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300460 return 0;
461 }
462 return -1;
463}
464
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300465static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300466 const __u8 buffer[][8], int len)
467{
468 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300469 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300470 len -= 8;
471 if (len <= 0)
472 break;
473 buffer++;
474 }
475}
476
477static void setbrightness(struct gspca_dev *gspca_dev)
478{
479 struct sd *sd = (struct sd *) gspca_dev;
480 __u8 value;
481
482 switch (sd->sensor) {
483 case SENSOR_OV6650: {
484 __u8 i2cOV6650[] =
485 {0xa0, 0x60, 0x06, 0x11, 0x99, 0x04, 0x94, 0x15};
486
487 i2cOV6650[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300488 if (i2c_w(gspca_dev, i2cOV6650) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300489 goto err;
490 break;
491 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300492 case SENSOR_OV7630_3:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300493 case SENSOR_OV7630: {
494 __u8 i2cOV[] =
495 {0xa0, 0x21, 0x06, 0x36, 0xbd, 0x06, 0xf6, 0x16};
496
497 /* change reg 0x06 */
498 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300499 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500 goto err;
501 break;
502 }
503 case SENSOR_PAS106: {
504 __u8 i2c1[] =
505 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
506
507 i2c1[3] = sd->brightness >> 3;
508 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300509 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300510 goto err;
511 i2c1[3] = 0x01;
512 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300513 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300514 goto err;
515 break;
516 }
517 case SENSOR_PAS202: {
518 /* __u8 i2cpexpo1[] =
519 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
520 __u8 i2cpexpo[] =
521 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
522 __u8 i2cp202[] =
523 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
524 static __u8 i2cpdoit[] =
525 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
526
527 /* change reg 0x10 */
528 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300529/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300530 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300531/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300533 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300534 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300535 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300536 goto err;
537 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300538 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300539 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300540 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300541 goto err;
542 break;
543 }
Hans de Goededcef3232008-07-10 10:40:53 -0300544 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300545 __u8 i2c[] =
546 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
547
548 value = 0xff - sd->brightness;
549 i2c[4] = value;
550 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300551 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300552 goto err;
553 break;
554 }
Hans de Goededcef3232008-07-10 10:40:53 -0300555 case SENSOR_TAS5110:
556 /* FIXME figure out howto control brightness on TAS5110 */
557 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300558 }
559 return;
560err:
561 PDEBUG(D_ERR, "i2c error brightness");
562}
Hans de Goededcef3232008-07-10 10:40:53 -0300563
564static void setsensorgain(struct gspca_dev *gspca_dev)
565{
566 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300567
568 switch (sd->sensor) {
569
570 case SENSOR_TAS5110: {
571 __u8 i2c[] =
572 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
573
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300574 i2c[4] = 255 - sd->gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300575 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300576 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300577 break;
578 }
Hans de Goededcef3232008-07-10 10:40:53 -0300579 case SENSOR_OV6650: {
580 __u8 i2c[] = {0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300581
582 i2c[3] = sd->gain >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300583 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300584 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300585 break;
586 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300587 case SENSOR_OV7630_3: {
588 __u8 i2c[] = {0xa0, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
589
590 i2c[3] = sd->gain >> 2;
591 if (i2c_w(gspca_dev, i2c) < 0)
592 goto err;
593 break;
594 }
Hans de Goededcef3232008-07-10 10:40:53 -0300595 }
596 return;
597err:
598 PDEBUG(D_ERR, "i2c error gain");
599}
600
601static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300602{
603 struct sd *sd = (struct sd *) gspca_dev;
604 __u8 gain;
605 __u8 rgb_value;
606
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300607 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300608
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300609 /* red and blue gain */
610 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300611 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300612 /* green gain */
613 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300614 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300615
616 if (sd->sensor_has_gain)
617 setsensorgain(gspca_dev);
618}
619
620static void setexposure(struct gspca_dev *gspca_dev)
621{
622 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300623
624 switch (sd->sensor) {
625 case SENSOR_TAS5110: {
626 __u8 reg;
627
628 /* register 19's high nibble contains the sn9c10x clock divider
629 The high nibble configures the no fps according to the
630 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300631 reg = 120 * sd->exposure / 1000;
632 if (reg < 2)
633 reg = 2;
634 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300635 reg = 15;
636 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300637 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300638 break;
639 }
Hans de Goededcef3232008-07-10 10:40:53 -0300640 case SENSOR_OV6650: {
Hans de Goedef4d52022008-07-15 09:36:42 -0300641 /* The ov6650 has 2 registers which both influence exposure,
642 first there is register 11, whose low nibble sets the no fps
643 according to: fps = 30 / (low_nibble + 1)
644
645 The fps configures the maximum exposure setting, but it is
646 possible to use less exposure then what the fps maximum
647 allows by setting register 10. register 10 configures the
648 actual exposure as quotient of the full exposure, with 0
649 being no exposure at all (not very usefull) and reg10_max
650 being max exposure possible at that framerate.
651
652 The code maps our 0 - 510 ms exposure ctrl to these 2
653 registers, trying to keep fps as high as possible.
654 */
655 __u8 i2c[] = {0xb0, 0x60, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
656 int reg10, reg11;
657 /* No clear idea why, but setting reg10 above this value
658 results in no change */
659 const int reg10_max = 0x4d;
660
661 reg11 = (60 * sd->exposure + 999) / 1000;
662 if (reg11 < 1)
663 reg11 = 1;
664 else if (reg11 > 16)
665 reg11 = 16;
666
667 /* frame exposure time in ms = 1000 * reg11 / 30 ->
668 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
669 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
670 if (reg10 < 1) /* 0 is a valid value, but is very _black_ */
671 reg10 = 1;
672 else if (reg10 > reg10_max)
673 reg10 = reg10_max;
674
675 /* Write reg 10 and reg11 low nibble */
676 i2c[3] = reg10;
677 i2c[4] |= reg11 - 1;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300678 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300679 PDEBUG(D_ERR, "i2c error exposure");
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300680 break;
681 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300682 case SENSOR_OV7630_3: {
683 __u8 i2c[] = {0xb0, 0x21, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
684 int reg10, reg11;
685 /* No clear idea why, but setting reg10 above this value
686 results in no change */
687 const int reg10_max = 0x4d;
688
689 reg11 = (60 * sd->exposure + 999) / 1000;
690 if (reg11 < 1)
691 reg11 = 1;
692 else if (reg11 > 16)
693 reg11 = 16;
694
695 /* frame exposure time in ms = 1000 * reg11 / 30 ->
696 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
697 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
698 if (reg10 < 1) /* 0 is a valid value, but is very _black_ */
699 reg10 = 1;
700 else if (reg10 > reg10_max)
701 reg10 = reg10_max;
702
703 /* Write reg 10 and reg11 low nibble */
704 i2c[3] = reg10;
705 i2c[4] |= reg11 - 1;
706 if (i2c_w(gspca_dev, i2c) < 0)
707 PDEBUG(D_ERR, "i2c error exposure");
708 break;
709 }
Hans de Goededcef3232008-07-10 10:40:53 -0300710 }
711}
712
713
714static void do_autogain(struct gspca_dev *gspca_dev)
715{
716 struct sd *sd = (struct sd *) gspca_dev;
717 int avg_lum = atomic_read(&sd->avg_lum);
718
719 if (avg_lum == -1)
720 return;
721
722 if (sd->autogain_ignore_frames > 0)
723 sd->autogain_ignore_frames--;
724 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
725 sd->brightness * DESIRED_AVG_LUM / 127,
726 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE))
727 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300728}
729
730/* this function is called at probe time */
731static int sd_config(struct gspca_dev *gspca_dev,
732 const struct usb_device_id *id)
733{
734 struct sd *sd = (struct sd *) gspca_dev;
735 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300736 __u16 product;
737 int sif = 0;
738
Hans de Goededcef3232008-07-10 10:40:53 -0300739 /* nctrls depends upon the sensor, so we use a per cam copy */
740 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
741 gspca_dev->sd_desc = &sd->sd_desc;
742
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300743 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300744 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300745 sd->autogain = AUTOGAIN_DEF; /* default is autogain active */
Hans de Goededcef3232008-07-10 10:40:53 -0300746
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300747 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300748/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300749/* case 0x0c45: * Sonix */
750 switch (product) {
751 case 0x6001: /* SN9C102 */
752 case 0x6005: /* SN9C101 */
753 case 0x6007: /* SN9C101 */
754 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300755 sd->sensor_has_gain = 1;
756 sd->sd_desc.nctrls = 4;
757 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300758 sif = 1;
759 break;
760 case 0x6009: /* SN9C101 */
761 case 0x600d: /* SN9C101 */
762 case 0x6029: /* SN9C101 */
763 sd->sensor = SENSOR_PAS106;
764 sif = 1;
765 break;
766 case 0x6011: /* SN9C101 - SN9C101G */
767 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300768 sd->sensor_has_gain = 1;
769 sd->sd_desc.nctrls = 4;
770 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300771 sif = 1;
772 break;
773 case 0x6019: /* SN9C101 */
774 case 0x602c: /* SN9C102 */
775 case 0x602e: /* SN9C102 */
776 sd->sensor = SENSOR_OV7630;
777 break;
778 case 0x60b0: /* SN9C103 */
779 sd->sensor = SENSOR_OV7630_3;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300780 sd->fr_h_sz = 18; /* size of frame header */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300781 sd->sensor_has_gain = 1;
782 sd->sd_desc.nctrls = 4;
783 sd->sd_desc.dq_callback = do_autogain;
784 sd->autogain = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300785 break;
786 case 0x6024: /* SN9C102 */
787 case 0x6025: /* SN9C102 */
788 sd->sensor = SENSOR_TAS5130CXX;
789 break;
790 case 0x6028: /* SN9C102 */
791 sd->sensor = SENSOR_PAS202;
792 break;
793 case 0x602d: /* SN9C102 */
794 sd->sensor = SENSOR_HV7131R;
795 break;
796 case 0x60af: /* SN9C103 */
797 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300798 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300799 break;
800 }
801/* break; */
802/* } */
803
804 cam = &gspca_dev->cam;
805 cam->dev_name = (char *) id->driver_info;
806 cam->epaddr = 0x01;
807 if (!sif) {
808 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300809 cam->nmodes = ARRAY_SIZE(vga_mode);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300810 if (sd->sensor == SENSOR_OV7630_3) {
811 /* We only have 320x240 & 640x480 */
812 cam->cam_mode++;
813 cam->nmodes--;
814 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300815 } else {
816 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300817 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300818 }
Hans de Goededcef3232008-07-10 10:40:53 -0300819 sd->brightness = BRIGHTNESS_DEF;
820 sd->gain = GAIN_DEF;
821 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300822 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300823 reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300824 return 0;
825}
826
827/* this function is called at open time */
828static int sd_open(struct gspca_dev *gspca_dev)
829{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300830 reg_r(gspca_dev, 0x00);
831 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300832 return -ENODEV;
833 return 0;
834}
835
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300836static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300837{
838 int i;
839 const __u8 *data;
840 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
841
842 i = ARRAY_SIZE(pas106_data);
843 data = pas106_data[0];
844 while (--i >= 0) {
845 memcpy(&i2c1[2], data, 2);
846 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300847 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300848 PDEBUG(D_ERR, "i2c error pas106");
849 data += 2;
850 }
851}
852
853/* -- start the camera -- */
854static void sd_start(struct gspca_dev *gspca_dev)
855{
856 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300857 int mode, l;
858 const __u8 *sn9c10x;
859 __u8 reg01, reg17;
860 __u8 reg17_19[3];
861
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300862 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300863 switch (sd->sensor) {
864 case SENSOR_HV7131R:
865 sn9c10x = initHv7131;
866 reg17_19[0] = 0x60;
867 reg17_19[1] = (mode << 4) | 0x8a;
868 reg17_19[2] = 0x20;
869 break;
870 case SENSOR_OV6650:
871 sn9c10x = initOv6650;
872 reg17_19[0] = 0x68;
873 reg17_19[1] = (mode << 4) | 0x8b;
874 reg17_19[2] = 0x20;
875 break;
876 case SENSOR_OV7630:
877 sn9c10x = initOv7630;
878 reg17_19[0] = 0x68;
879 reg17_19[1] = (mode << 4) | COMP2;
880 reg17_19[2] = MCK_INIT1;
881 break;
882 case SENSOR_OV7630_3:
883 sn9c10x = initOv7630_3;
884 reg17_19[0] = 0x68;
885 reg17_19[1] = (mode << 4) | COMP2;
886 reg17_19[2] = MCK_INIT1;
887 break;
888 case SENSOR_PAS106:
889 sn9c10x = initPas106;
890 reg17_19[0] = 0x24; /* 0x28 */
891 reg17_19[1] = (mode << 4) | COMP1;
892 reg17_19[2] = MCK_INIT1;
893 break;
894 case SENSOR_PAS202:
895 sn9c10x = initPas202;
896 reg17_19[0] = mode ? 0x24 : 0x20;
897 reg17_19[1] = (mode << 4) | 0x89;
898 reg17_19[2] = 0x20;
899 break;
900 case SENSOR_TAS5110:
901 sn9c10x = initTas5110;
902 reg17_19[0] = 0x60;
903 reg17_19[1] = (mode << 4) | 0x86;
904 reg17_19[2] = 0x2b; /* 0xf3; */
905 break;
906 default:
907/* case SENSOR_TAS5130CXX: */
908 sn9c10x = initTas5130;
909 reg17_19[0] = 0x60;
910 reg17_19[1] = (mode << 4) | COMP;
911 reg17_19[2] = mode ? 0x23 : 0x43;
912 break;
913 }
914 switch (sd->sensor) {
915 case SENSOR_OV7630:
916 reg01 = 0x06;
917 reg17 = 0x29;
918 l = 0x10;
919 break;
920 case SENSOR_OV7630_3:
921 reg01 = 0x44;
922 reg17 = 0x68;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300923 l = sizeof initOv7630_3;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300924 break;
925 default:
926 reg01 = sn9c10x[0];
927 reg17 = sn9c10x[0x17 - 1];
928 l = 0x1f;
929 break;
930 }
931
932 /* reg 0x01 bit 2 video transfert on */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300933 reg_w(gspca_dev, 0x01, &reg01, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300934 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300935 reg_w(gspca_dev, 0x17, &reg17, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300936/*fixme: for ov7630 102
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300937 reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300938 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300939 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300940 switch (sd->sensor) {
941 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300942 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300943 sizeof hv7131_sensor_init);
944 break;
945 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300946 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300947 sizeof ov6650_sensor_init);
948 break;
949 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300950 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300951 sizeof ov7630_sensor_init_com);
952 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300953 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300954 sizeof ov7630_sensor_init);
955 break;
956 case SENSOR_OV7630_3:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300957 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300958 sizeof ov7630_sensor_init_com);
959 msleep(200);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300960 i2c_w_vector(gspca_dev, ov7630_sensor_init_3[mode],
961 sizeof ov7630_sensor_init_3[mode]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300962 break;
963 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300964 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300965 break;
966 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300967 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300968 sizeof pas202_sensor_init);
969 break;
970 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300971 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300972 sizeof tas5110_sensor_init);
973 break;
974 default:
975/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300976 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300977 sizeof tas5130_sensor_init);
978 break;
979 }
Hans de Goede3647fea2008-07-15 05:36:30 -0300980 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
981 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300982 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300983 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -0300984 /* H_start */
985 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
986 /* V_START */
987 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300988 /* reset 0x17 SensorClk enable inv Clk 0x60 */
989 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300990 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300991 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -0300992 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300993 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300994 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300995 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300996 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300997 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300998 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300999 msleep(20);
1000
Hans de Goededcef3232008-07-10 10:40:53 -03001001 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001002 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001003 setexposure(gspca_dev);
1004
1005 sd->autogain_ignore_frames = 0;
1006 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001007}
1008
1009static void sd_stopN(struct gspca_dev *gspca_dev)
1010{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -03001011 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001012
1013 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001014 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001015}
1016
1017static void sd_stop0(struct gspca_dev *gspca_dev)
1018{
1019}
1020
1021static void sd_close(struct gspca_dev *gspca_dev)
1022{
1023}
1024
1025static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1026 struct gspca_frame *frame, /* target */
1027 unsigned char *data, /* isoc packet */
1028 int len) /* iso packet length */
1029{
Hans de Goede0d2a7222008-07-03 08:15:22 -03001030 int i;
Hans de Goededcef3232008-07-10 10:40:53 -03001031 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001032
1033 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -03001034 for (i = 0; i < len - 6; i++) {
1035 if (data[0 + i] == 0xff
1036 && data[1 + i] == 0xff
1037 && data[2 + i] == 0x00
1038 && data[3 + i] == 0xc4
1039 && data[4 + i] == 0xc4
1040 && data[5 + i] == 0x96) { /* start of frame */
1041 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
1042 frame, data, 0);
Hans de Goededcef3232008-07-10 10:40:53 -03001043 if (i < (len - 10)) {
1044 atomic_set(&sd->avg_lum, data[i + 8] +
1045 (data[i + 9] << 8));
1046 } else {
1047 atomic_set(&sd->avg_lum, -1);
1048#ifdef CONFIG_VIDEO_ADV_DEBUG
1049 PDEBUG(D_STREAM, "packet too short to "
1050 "get avg brightness");
1051#endif
1052 }
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -03001053 data += i + sd->fr_h_sz;
1054 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001055 gspca_frame_add(gspca_dev, FIRST_PACKET,
1056 frame, data, len);
1057 return;
1058 }
1059 }
1060 }
1061 gspca_frame_add(gspca_dev, INTER_PACKET,
1062 frame, data, len);
1063}
1064
1065static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1066{
1067 struct sd *sd = (struct sd *) gspca_dev;
1068
1069 sd->brightness = val;
1070 if (gspca_dev->streaming)
1071 setbrightness(gspca_dev);
1072 return 0;
1073}
1074
1075static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1076{
1077 struct sd *sd = (struct sd *) gspca_dev;
1078
1079 *val = sd->brightness;
1080 return 0;
1081}
1082
Hans de Goededcef3232008-07-10 10:40:53 -03001083static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001084{
1085 struct sd *sd = (struct sd *) gspca_dev;
1086
Hans de Goededcef3232008-07-10 10:40:53 -03001087 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001088 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001089 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001090 return 0;
1091}
1092
Hans de Goededcef3232008-07-10 10:40:53 -03001093static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001094{
1095 struct sd *sd = (struct sd *) gspca_dev;
1096
Hans de Goededcef3232008-07-10 10:40:53 -03001097 *val = sd->gain;
1098 return 0;
1099}
1100
1101static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1102{
1103 struct sd *sd = (struct sd *) gspca_dev;
1104
1105 sd->exposure = val;
1106 if (gspca_dev->streaming)
1107 setexposure(gspca_dev);
1108 return 0;
1109}
1110
1111static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1112{
1113 struct sd *sd = (struct sd *) gspca_dev;
1114
1115 *val = sd->exposure;
1116 return 0;
1117}
1118
1119static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1120{
1121 struct sd *sd = (struct sd *) gspca_dev;
1122
1123 sd->autogain = val;
1124 /* when switching to autogain set defaults to make sure
1125 we are on a valid point of the autogain gain /
1126 exposure knee graph, and give this change time to
1127 take effect before doing autogain. */
1128 if (sd->autogain) {
1129 sd->exposure = EXPOSURE_DEF;
1130 sd->gain = GAIN_DEF;
1131 if (gspca_dev->streaming) {
1132 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1133 setexposure(gspca_dev);
1134 setgain(gspca_dev);
1135 }
1136 }
1137
1138 return 0;
1139}
1140
1141static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1142{
1143 struct sd *sd = (struct sd *) gspca_dev;
1144
1145 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001146 return 0;
1147}
1148
1149/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001150static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001151 .name = MODULE_NAME,
1152 .ctrls = sd_ctrls,
1153 .nctrls = ARRAY_SIZE(sd_ctrls),
1154 .config = sd_config,
1155 .open = sd_open,
1156 .start = sd_start,
1157 .stopN = sd_stopN,
1158 .stop0 = sd_stop0,
1159 .close = sd_close,
1160 .pkt_scan = sd_pkt_scan,
1161};
1162
1163/* -- module initialisation -- */
1164#define DVNM(name) .driver_info = (kernel_ulong_t) name
1165static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001166#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001167 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1168 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1169 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1170 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1171 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001172 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001173 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1174 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1175 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1176 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1177 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1178 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1179 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1180 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1181 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1182 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001183#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001184 {}
1185};
1186MODULE_DEVICE_TABLE(usb, device_table);
1187
1188/* -- device connect -- */
1189static int sd_probe(struct usb_interface *intf,
1190 const struct usb_device_id *id)
1191{
1192 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1193 THIS_MODULE);
1194}
1195
1196static struct usb_driver sd_driver = {
1197 .name = MODULE_NAME,
1198 .id_table = device_table,
1199 .probe = sd_probe,
1200 .disconnect = gspca_disconnect,
1201};
1202
1203/* -- module insert / remove -- */
1204static int __init sd_mod_init(void)
1205{
1206 if (usb_register(&sd_driver) < 0)
1207 return -1;
1208 PDEBUG(D_PROBE, "v%s registered", version);
1209 return 0;
1210}
1211static void __exit sd_mod_exit(void)
1212{
1213 usb_deregister(&sd_driver);
1214 PDEBUG(D_PROBE, "deregistered");
1215}
1216
1217module_init(sd_mod_init);
1218module_exit(sd_mod_exit);