blob: a512772664a392672255a9296ea1aa6a3b514392 [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);
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300459 if (gspca_dev->usb_buf[0] & 0x04) {
460 if (gspca_dev->usb_buf[0] & 0x08)
461 return -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300462 return 0;
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300463 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300464 }
465 return -1;
466}
467
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300468static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300469 const __u8 buffer[][8], int len)
470{
471 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300472 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300473 len -= 8;
474 if (len <= 0)
475 break;
476 buffer++;
477 }
478}
479
480static void setbrightness(struct gspca_dev *gspca_dev)
481{
482 struct sd *sd = (struct sd *) gspca_dev;
483 __u8 value;
484
485 switch (sd->sensor) {
486 case SENSOR_OV6650: {
487 __u8 i2cOV6650[] =
488 {0xa0, 0x60, 0x06, 0x11, 0x99, 0x04, 0x94, 0x15};
489
490 i2cOV6650[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300491 if (i2c_w(gspca_dev, i2cOV6650) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300492 goto err;
493 break;
494 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300495 case SENSOR_OV7630_3:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300496 case SENSOR_OV7630: {
497 __u8 i2cOV[] =
498 {0xa0, 0x21, 0x06, 0x36, 0xbd, 0x06, 0xf6, 0x16};
499
500 /* change reg 0x06 */
501 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300502 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503 goto err;
504 break;
505 }
506 case SENSOR_PAS106: {
507 __u8 i2c1[] =
508 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
509
510 i2c1[3] = sd->brightness >> 3;
511 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300512 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300513 goto err;
514 i2c1[3] = 0x01;
515 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300516 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517 goto err;
518 break;
519 }
520 case SENSOR_PAS202: {
521 /* __u8 i2cpexpo1[] =
522 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
523 __u8 i2cpexpo[] =
524 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
525 __u8 i2cp202[] =
526 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
527 static __u8 i2cpdoit[] =
528 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
529
530 /* change reg 0x10 */
531 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300532/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300533 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300534/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300535 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300536 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300537 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300538 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300539 goto err;
540 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300541 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300542 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300543 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300544 goto err;
545 break;
546 }
Hans de Goededcef3232008-07-10 10:40:53 -0300547 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300548 __u8 i2c[] =
549 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
550
551 value = 0xff - sd->brightness;
552 i2c[4] = value;
553 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300554 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300555 goto err;
556 break;
557 }
Hans de Goededcef3232008-07-10 10:40:53 -0300558 case SENSOR_TAS5110:
559 /* FIXME figure out howto control brightness on TAS5110 */
560 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300561 }
562 return;
563err:
564 PDEBUG(D_ERR, "i2c error brightness");
565}
Hans de Goededcef3232008-07-10 10:40:53 -0300566
567static void setsensorgain(struct gspca_dev *gspca_dev)
568{
569 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300570
571 switch (sd->sensor) {
572
573 case SENSOR_TAS5110: {
574 __u8 i2c[] =
575 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
576
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300577 i2c[4] = 255 - sd->gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300578 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300579 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300580 break;
581 }
Hans de Goededcef3232008-07-10 10:40:53 -0300582 case SENSOR_OV6650: {
583 __u8 i2c[] = {0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300584
585 i2c[3] = sd->gain >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300586 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300587 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300588 break;
589 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300590 case SENSOR_OV7630_3: {
591 __u8 i2c[] = {0xa0, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
592
593 i2c[3] = sd->gain >> 2;
594 if (i2c_w(gspca_dev, i2c) < 0)
595 goto err;
596 break;
597 }
Hans de Goededcef3232008-07-10 10:40:53 -0300598 }
599 return;
600err:
601 PDEBUG(D_ERR, "i2c error gain");
602}
603
604static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300605{
606 struct sd *sd = (struct sd *) gspca_dev;
607 __u8 gain;
608 __u8 rgb_value;
609
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300610 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300611
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300612 /* red and blue gain */
613 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300614 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300615 /* green gain */
616 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300617 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300618
619 if (sd->sensor_has_gain)
620 setsensorgain(gspca_dev);
621}
622
623static void setexposure(struct gspca_dev *gspca_dev)
624{
625 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300626
627 switch (sd->sensor) {
628 case SENSOR_TAS5110: {
629 __u8 reg;
630
631 /* register 19's high nibble contains the sn9c10x clock divider
632 The high nibble configures the no fps according to the
633 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300634 reg = 120 * sd->exposure / 1000;
635 if (reg < 2)
636 reg = 2;
637 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300638 reg = 15;
639 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300640 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300641 break;
642 }
Hans de Goededcef3232008-07-10 10:40:53 -0300643 case SENSOR_OV6650: {
Hans de Goedef4d52022008-07-15 09:36:42 -0300644 /* The ov6650 has 2 registers which both influence exposure,
645 first there is register 11, whose low nibble sets the no fps
646 according to: fps = 30 / (low_nibble + 1)
647
648 The fps configures the maximum exposure setting, but it is
649 possible to use less exposure then what the fps maximum
650 allows by setting register 10. register 10 configures the
651 actual exposure as quotient of the full exposure, with 0
652 being no exposure at all (not very usefull) and reg10_max
653 being max exposure possible at that framerate.
654
655 The code maps our 0 - 510 ms exposure ctrl to these 2
656 registers, trying to keep fps as high as possible.
657 */
658 __u8 i2c[] = {0xb0, 0x60, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
659 int reg10, reg11;
660 /* No clear idea why, but setting reg10 above this value
661 results in no change */
662 const int reg10_max = 0x4d;
663
664 reg11 = (60 * sd->exposure + 999) / 1000;
665 if (reg11 < 1)
666 reg11 = 1;
667 else if (reg11 > 16)
668 reg11 = 16;
669
670 /* frame exposure time in ms = 1000 * reg11 / 30 ->
671 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
672 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
673 if (reg10 < 1) /* 0 is a valid value, but is very _black_ */
674 reg10 = 1;
675 else if (reg10 > reg10_max)
676 reg10 = reg10_max;
677
678 /* Write reg 10 and reg11 low nibble */
679 i2c[3] = reg10;
680 i2c[4] |= reg11 - 1;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300681 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300682 PDEBUG(D_ERR, "i2c error exposure");
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300683 break;
684 }
Andoni Zubimendi794af522008-07-16 08:33:14 -0300685 case SENSOR_OV7630_3: {
686 __u8 i2c[] = {0xb0, 0x21, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
687 int reg10, reg11;
688 /* No clear idea why, but setting reg10 above this value
689 results in no change */
690 const int reg10_max = 0x4d;
691
692 reg11 = (60 * sd->exposure + 999) / 1000;
693 if (reg11 < 1)
694 reg11 = 1;
695 else if (reg11 > 16)
696 reg11 = 16;
697
698 /* frame exposure time in ms = 1000 * reg11 / 30 ->
699 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
700 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
701 if (reg10 < 1) /* 0 is a valid value, but is very _black_ */
702 reg10 = 1;
703 else if (reg10 > reg10_max)
704 reg10 = reg10_max;
705
706 /* Write reg 10 and reg11 low nibble */
707 i2c[3] = reg10;
708 i2c[4] |= reg11 - 1;
709 if (i2c_w(gspca_dev, i2c) < 0)
710 PDEBUG(D_ERR, "i2c error exposure");
711 break;
712 }
Hans de Goededcef3232008-07-10 10:40:53 -0300713 }
714}
715
716
717static void do_autogain(struct gspca_dev *gspca_dev)
718{
719 struct sd *sd = (struct sd *) gspca_dev;
720 int avg_lum = atomic_read(&sd->avg_lum);
721
722 if (avg_lum == -1)
723 return;
724
725 if (sd->autogain_ignore_frames > 0)
726 sd->autogain_ignore_frames--;
727 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
728 sd->brightness * DESIRED_AVG_LUM / 127,
729 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE))
730 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300731}
732
733/* this function is called at probe time */
734static int sd_config(struct gspca_dev *gspca_dev,
735 const struct usb_device_id *id)
736{
737 struct sd *sd = (struct sd *) gspca_dev;
738 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300739 __u16 product;
740 int sif = 0;
741
Hans de Goededcef3232008-07-10 10:40:53 -0300742 /* nctrls depends upon the sensor, so we use a per cam copy */
743 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
744 gspca_dev->sd_desc = &sd->sd_desc;
745
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300746 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300747 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300748 sd->autogain = AUTOGAIN_DEF; /* default is autogain active */
Hans de Goededcef3232008-07-10 10:40:53 -0300749
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300750 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300751/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300752/* case 0x0c45: * Sonix */
753 switch (product) {
754 case 0x6001: /* SN9C102 */
755 case 0x6005: /* SN9C101 */
756 case 0x6007: /* SN9C101 */
757 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300758 sd->sensor_has_gain = 1;
759 sd->sd_desc.nctrls = 4;
760 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300761 sif = 1;
762 break;
763 case 0x6009: /* SN9C101 */
764 case 0x600d: /* SN9C101 */
765 case 0x6029: /* SN9C101 */
766 sd->sensor = SENSOR_PAS106;
767 sif = 1;
768 break;
769 case 0x6011: /* SN9C101 - SN9C101G */
770 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300771 sd->sensor_has_gain = 1;
772 sd->sd_desc.nctrls = 4;
773 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300774 sif = 1;
775 break;
776 case 0x6019: /* SN9C101 */
777 case 0x602c: /* SN9C102 */
778 case 0x602e: /* SN9C102 */
779 sd->sensor = SENSOR_OV7630;
780 break;
781 case 0x60b0: /* SN9C103 */
782 sd->sensor = SENSOR_OV7630_3;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300783 sd->fr_h_sz = 18; /* size of frame header */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300784 sd->sensor_has_gain = 1;
785 sd->sd_desc.nctrls = 4;
786 sd->sd_desc.dq_callback = do_autogain;
787 sd->autogain = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300788 break;
789 case 0x6024: /* SN9C102 */
790 case 0x6025: /* SN9C102 */
791 sd->sensor = SENSOR_TAS5130CXX;
792 break;
793 case 0x6028: /* SN9C102 */
794 sd->sensor = SENSOR_PAS202;
795 break;
796 case 0x602d: /* SN9C102 */
797 sd->sensor = SENSOR_HV7131R;
798 break;
799 case 0x60af: /* SN9C103 */
800 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300801 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300802 break;
803 }
804/* break; */
805/* } */
806
807 cam = &gspca_dev->cam;
808 cam->dev_name = (char *) id->driver_info;
809 cam->epaddr = 0x01;
810 if (!sif) {
811 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300812 cam->nmodes = ARRAY_SIZE(vga_mode);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300813 if (sd->sensor == SENSOR_OV7630_3) {
814 /* We only have 320x240 & 640x480 */
815 cam->cam_mode++;
816 cam->nmodes--;
817 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300818 } else {
819 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300820 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300821 }
Hans de Goededcef3232008-07-10 10:40:53 -0300822 sd->brightness = BRIGHTNESS_DEF;
823 sd->gain = GAIN_DEF;
824 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300825 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300826 reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300827 return 0;
828}
829
830/* this function is called at open time */
831static int sd_open(struct gspca_dev *gspca_dev)
832{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300833 reg_r(gspca_dev, 0x00);
834 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300835 return -ENODEV;
836 return 0;
837}
838
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300839static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300840{
841 int i;
842 const __u8 *data;
843 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
844
845 i = ARRAY_SIZE(pas106_data);
846 data = pas106_data[0];
847 while (--i >= 0) {
848 memcpy(&i2c1[2], data, 2);
849 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300850 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300851 PDEBUG(D_ERR, "i2c error pas106");
852 data += 2;
853 }
854}
855
856/* -- start the camera -- */
857static void sd_start(struct gspca_dev *gspca_dev)
858{
859 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300860 int mode, l;
861 const __u8 *sn9c10x;
862 __u8 reg01, reg17;
863 __u8 reg17_19[3];
864
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300865 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300866 switch (sd->sensor) {
867 case SENSOR_HV7131R:
868 sn9c10x = initHv7131;
869 reg17_19[0] = 0x60;
870 reg17_19[1] = (mode << 4) | 0x8a;
871 reg17_19[2] = 0x20;
872 break;
873 case SENSOR_OV6650:
874 sn9c10x = initOv6650;
875 reg17_19[0] = 0x68;
876 reg17_19[1] = (mode << 4) | 0x8b;
877 reg17_19[2] = 0x20;
878 break;
879 case SENSOR_OV7630:
880 sn9c10x = initOv7630;
881 reg17_19[0] = 0x68;
882 reg17_19[1] = (mode << 4) | COMP2;
883 reg17_19[2] = MCK_INIT1;
884 break;
885 case SENSOR_OV7630_3:
886 sn9c10x = initOv7630_3;
887 reg17_19[0] = 0x68;
888 reg17_19[1] = (mode << 4) | COMP2;
889 reg17_19[2] = MCK_INIT1;
890 break;
891 case SENSOR_PAS106:
892 sn9c10x = initPas106;
893 reg17_19[0] = 0x24; /* 0x28 */
894 reg17_19[1] = (mode << 4) | COMP1;
895 reg17_19[2] = MCK_INIT1;
896 break;
897 case SENSOR_PAS202:
898 sn9c10x = initPas202;
899 reg17_19[0] = mode ? 0x24 : 0x20;
900 reg17_19[1] = (mode << 4) | 0x89;
901 reg17_19[2] = 0x20;
902 break;
903 case SENSOR_TAS5110:
904 sn9c10x = initTas5110;
905 reg17_19[0] = 0x60;
906 reg17_19[1] = (mode << 4) | 0x86;
907 reg17_19[2] = 0x2b; /* 0xf3; */
908 break;
909 default:
910/* case SENSOR_TAS5130CXX: */
911 sn9c10x = initTas5130;
912 reg17_19[0] = 0x60;
913 reg17_19[1] = (mode << 4) | COMP;
914 reg17_19[2] = mode ? 0x23 : 0x43;
915 break;
916 }
917 switch (sd->sensor) {
918 case SENSOR_OV7630:
919 reg01 = 0x06;
920 reg17 = 0x29;
921 l = 0x10;
922 break;
923 case SENSOR_OV7630_3:
924 reg01 = 0x44;
925 reg17 = 0x68;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300926 l = sizeof initOv7630_3;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300927 break;
928 default:
929 reg01 = sn9c10x[0];
930 reg17 = sn9c10x[0x17 - 1];
931 l = 0x1f;
932 break;
933 }
934
935 /* reg 0x01 bit 2 video transfert on */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300936 reg_w(gspca_dev, 0x01, &reg01, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300937 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300938 reg_w(gspca_dev, 0x17, &reg17, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300939/*fixme: for ov7630 102
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300940 reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300941 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300942 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300943 switch (sd->sensor) {
944 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300945 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300946 sizeof hv7131_sensor_init);
947 break;
948 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300949 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300950 sizeof ov6650_sensor_init);
951 break;
952 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300953 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300954 sizeof ov7630_sensor_init_com);
955 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300956 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300957 sizeof ov7630_sensor_init);
958 break;
959 case SENSOR_OV7630_3:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300960 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300961 sizeof ov7630_sensor_init_com);
962 msleep(200);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300963 i2c_w_vector(gspca_dev, ov7630_sensor_init_3[mode],
964 sizeof ov7630_sensor_init_3[mode]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300965 break;
966 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300967 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300968 break;
969 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300970 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300971 sizeof pas202_sensor_init);
972 break;
973 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300974 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300975 sizeof tas5110_sensor_init);
976 break;
977 default:
978/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300979 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300980 sizeof tas5130_sensor_init);
981 break;
982 }
Hans de Goede3647fea2008-07-15 05:36:30 -0300983 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
984 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300985 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300986 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -0300987 /* H_start */
988 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
989 /* V_START */
990 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300991 /* reset 0x17 SensorClk enable inv Clk 0x60 */
992 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300993 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300994 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -0300995 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300996 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300997 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300998 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300999 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001000 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001001 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001002 msleep(20);
1003
Hans de Goededcef3232008-07-10 10:40:53 -03001004 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001005 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -03001006 setexposure(gspca_dev);
1007
1008 sd->autogain_ignore_frames = 0;
1009 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001010}
1011
1012static void sd_stopN(struct gspca_dev *gspca_dev)
1013{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -03001014 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001015
1016 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001017 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001018}
1019
1020static void sd_stop0(struct gspca_dev *gspca_dev)
1021{
1022}
1023
1024static void sd_close(struct gspca_dev *gspca_dev)
1025{
1026}
1027
1028static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1029 struct gspca_frame *frame, /* target */
1030 unsigned char *data, /* isoc packet */
1031 int len) /* iso packet length */
1032{
Hans de Goede0d2a7222008-07-03 08:15:22 -03001033 int i;
Hans de Goededcef3232008-07-10 10:40:53 -03001034 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001035
Hans de Goedec36260ee2008-07-16 09:56:07 -03001036 /* frames start with:
1037 * ff ff 00 c4 c4 96 synchro
1038 * 00 (unknown)
1039 * xx (frame sequence / size / compression)
1040 * (xx) (idem - extra byte for sn9c103)
1041 * ll mm brightness sum inside auto exposure
1042 * ll mm brightness sum outside auto exposure
1043 * (xx xx xx xx xx) audio values for snc103
1044 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001045 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -03001046 for (i = 0; i < len - 6; i++) {
1047 if (data[0 + i] == 0xff
1048 && data[1 + i] == 0xff
1049 && data[2 + i] == 0x00
1050 && data[3 + i] == 0xc4
1051 && data[4 + i] == 0xc4
1052 && data[5 + i] == 0x96) { /* start of frame */
1053 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
1054 frame, data, 0);
Hans de Goedec36260ee2008-07-16 09:56:07 -03001055 if (len - i < sd->fr_h_sz) {
1056 atomic_set(&sd->avg_lum, -1);
1057 PDEBUG(D_STREAM, "packet too short to"
1058 " get avg brightness");
1059 } else if (sd->fr_h_sz == 12) {
1060 atomic_set(&sd->avg_lum,
1061 data[i + 8] +
Hans de Goededcef3232008-07-10 10:40:53 -03001062 (data[i + 9] << 8));
1063 } else {
Hans de Goedec36260ee2008-07-16 09:56:07 -03001064 atomic_set(&sd->avg_lum,
1065 data[i + 9] +
1066 (data[i + 10] << 8));
Hans de Goededcef3232008-07-10 10:40:53 -03001067 }
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -03001068 data += i + sd->fr_h_sz;
1069 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001070 gspca_frame_add(gspca_dev, FIRST_PACKET,
1071 frame, data, len);
1072 return;
1073 }
1074 }
1075 }
1076 gspca_frame_add(gspca_dev, INTER_PACKET,
1077 frame, data, len);
1078}
1079
1080static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1081{
1082 struct sd *sd = (struct sd *) gspca_dev;
1083
1084 sd->brightness = val;
1085 if (gspca_dev->streaming)
1086 setbrightness(gspca_dev);
1087 return 0;
1088}
1089
1090static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1091{
1092 struct sd *sd = (struct sd *) gspca_dev;
1093
1094 *val = sd->brightness;
1095 return 0;
1096}
1097
Hans de Goededcef3232008-07-10 10:40:53 -03001098static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001099{
1100 struct sd *sd = (struct sd *) gspca_dev;
1101
Hans de Goededcef3232008-07-10 10:40:53 -03001102 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001103 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001104 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001105 return 0;
1106}
1107
Hans de Goededcef3232008-07-10 10:40:53 -03001108static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001109{
1110 struct sd *sd = (struct sd *) gspca_dev;
1111
Hans de Goededcef3232008-07-10 10:40:53 -03001112 *val = sd->gain;
1113 return 0;
1114}
1115
1116static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1117{
1118 struct sd *sd = (struct sd *) gspca_dev;
1119
1120 sd->exposure = val;
1121 if (gspca_dev->streaming)
1122 setexposure(gspca_dev);
1123 return 0;
1124}
1125
1126static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1127{
1128 struct sd *sd = (struct sd *) gspca_dev;
1129
1130 *val = sd->exposure;
1131 return 0;
1132}
1133
1134static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1135{
1136 struct sd *sd = (struct sd *) gspca_dev;
1137
1138 sd->autogain = val;
1139 /* when switching to autogain set defaults to make sure
1140 we are on a valid point of the autogain gain /
1141 exposure knee graph, and give this change time to
1142 take effect before doing autogain. */
1143 if (sd->autogain) {
1144 sd->exposure = EXPOSURE_DEF;
1145 sd->gain = GAIN_DEF;
1146 if (gspca_dev->streaming) {
1147 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1148 setexposure(gspca_dev);
1149 setgain(gspca_dev);
1150 }
1151 }
1152
1153 return 0;
1154}
1155
1156static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1157{
1158 struct sd *sd = (struct sd *) gspca_dev;
1159
1160 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001161 return 0;
1162}
1163
1164/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001165static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001166 .name = MODULE_NAME,
1167 .ctrls = sd_ctrls,
1168 .nctrls = ARRAY_SIZE(sd_ctrls),
1169 .config = sd_config,
1170 .open = sd_open,
1171 .start = sd_start,
1172 .stopN = sd_stopN,
1173 .stop0 = sd_stop0,
1174 .close = sd_close,
1175 .pkt_scan = sd_pkt_scan,
1176};
1177
1178/* -- module initialisation -- */
1179#define DVNM(name) .driver_info = (kernel_ulong_t) name
1180static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001181#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001182 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1183 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1184 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1185 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1186 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001187 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001188 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1189 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1190 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1191 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1192 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1193 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1194 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1195 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1196 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1197 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001198#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001199 {}
1200};
1201MODULE_DEVICE_TABLE(usb, device_table);
1202
1203/* -- device connect -- */
1204static int sd_probe(struct usb_interface *intf,
1205 const struct usb_device_id *id)
1206{
1207 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1208 THIS_MODULE);
1209}
1210
1211static struct usb_driver sd_driver = {
1212 .name = MODULE_NAME,
1213 .id_table = device_table,
1214 .probe = sd_probe,
1215 .disconnect = gspca_disconnect,
1216};
1217
1218/* -- module insert / remove -- */
1219static int __init sd_mod_init(void)
1220{
1221 if (usb_register(&sd_driver) < 0)
1222 return -1;
1223 PDEBUG(D_PROBE, "v%s registered", version);
1224 return 0;
1225}
1226static void __exit sd_mod_exit(void)
1227{
1228 usb_deregister(&sd_driver);
1229 PDEBUG(D_PROBE, "deregistered");
1230}
1231
1232module_init(sd_mod_init);
1233module_exit(sd_mod_exit);