2 * sonix sn9c102 (bayer) library
3 * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
4 * Add Pas106 Stefano Mozzi (C) 2004
6 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
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
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.
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
23 #define MODULE_NAME "sonixb"
27 #define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 8)
28 static const char version
[] = "2.1.8";
30 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
31 MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
32 MODULE_LICENSE("GPL");
34 /* specific webcam descriptor */
36 struct gspca_dev gspca_dev
; /* !! must be the first item */
38 struct sd_desc sd_desc
; /* our nctrls differ dependend upon the
39 sensor, so we use a per cam copy */
43 unsigned char exposure
;
44 unsigned char brightness
;
45 unsigned char autogain
;
46 unsigned char autogain_ignore_frames
;
47 unsigned char freq
; /* light freq filter setting */
49 unsigned char fr_h_sz
; /* size of frame header */
50 char sensor
; /* Type of image sensor chip */
51 #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
64 #define COMP 0xc7 /* 0x87 //0x07 */
65 #define COMP1 0xc9 /* 0x89 //0x09 */
68 #define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
72 /* We calculate the autogain at the end of the transfer of a frame, at this
73 moment a frame with the old settings is being transmitted, and a frame is
74 being captured with the old settings. So if we adjust the autogain we must
75 ignore atleast the 2 next frames for the new settings to come into effect
76 before doing any other adjustments */
77 #define AUTOGAIN_IGNORE_FRAMES 3
78 #define AUTOGAIN_DEADZONE 1000
79 #define DESIRED_AVG_LUM 7000
81 /* V4L2 controls supported by the driver */
82 static int sd_setbrightness(struct gspca_dev
*gspca_dev
, __s32 val
);
83 static int sd_getbrightness(struct gspca_dev
*gspca_dev
, __s32
*val
);
84 static int sd_setgain(struct gspca_dev
*gspca_dev
, __s32 val
);
85 static int sd_getgain(struct gspca_dev
*gspca_dev
, __s32
*val
);
86 static int sd_setexposure(struct gspca_dev
*gspca_dev
, __s32 val
);
87 static int sd_getexposure(struct gspca_dev
*gspca_dev
, __s32
*val
);
88 static int sd_setautogain(struct gspca_dev
*gspca_dev
, __s32 val
);
89 static int sd_getautogain(struct gspca_dev
*gspca_dev
, __s32
*val
);
90 static int sd_setfreq(struct gspca_dev
*gspca_dev
, __s32 val
);
91 static int sd_getfreq(struct gspca_dev
*gspca_dev
, __s32
*val
);
93 static struct ctrl sd_ctrls
[] = {
96 .id
= V4L2_CID_BRIGHTNESS
,
97 .type
= V4L2_CTRL_TYPE_INTEGER
,
102 #define BRIGHTNESS_DEF 127
103 .default_value
= BRIGHTNESS_DEF
,
105 .set
= sd_setbrightness
,
106 .get
= sd_getbrightness
,
111 .type
= V4L2_CTRL_TYPE_INTEGER
,
117 #define GAIN_KNEE 200
118 .default_value
= GAIN_DEF
,
125 .id
= V4L2_CID_EXPOSURE
,
126 .type
= V4L2_CTRL_TYPE_INTEGER
,
128 #define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
129 #define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
133 .default_value
= EXPOSURE_DEF
,
136 .set
= sd_setexposure
,
137 .get
= sd_getexposure
,
141 .id
= V4L2_CID_AUTOGAIN
,
142 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
143 .name
= "Automatic Gain (and Exposure)",
147 #define AUTOGAIN_DEF 1
148 .default_value
= AUTOGAIN_DEF
,
151 .set
= sd_setautogain
,
152 .get
= sd_getautogain
,
156 .id
= V4L2_CID_POWER_LINE_FREQUENCY
,
157 .type
= V4L2_CTRL_TYPE_MENU
,
158 .name
= "Light frequency filter",
160 .maximum
= 2, /* 0: 0, 1: 50Hz, 2:60Hz */
163 .default_value
= FREQ_DEF
,
170 static struct v4l2_pix_format vga_mode
[] = {
171 {160, 120, V4L2_PIX_FMT_SN9C10X
, V4L2_FIELD_NONE
,
173 .sizeimage
= 160 * 120,
174 .colorspace
= V4L2_COLORSPACE_SRGB
,
176 {320, 240, V4L2_PIX_FMT_SN9C10X
, V4L2_FIELD_NONE
,
178 .sizeimage
= 320 * 240,
179 .colorspace
= V4L2_COLORSPACE_SRGB
,
181 {640, 480, V4L2_PIX_FMT_SN9C10X
, V4L2_FIELD_NONE
,
183 .sizeimage
= 640 * 480,
184 .colorspace
= V4L2_COLORSPACE_SRGB
,
187 static struct v4l2_pix_format sif_mode
[] = {
188 {176, 144, V4L2_PIX_FMT_SN9C10X
, V4L2_FIELD_NONE
,
190 .sizeimage
= 176 * 144,
191 .colorspace
= V4L2_COLORSPACE_SRGB
,
193 {352, 288, V4L2_PIX_FMT_SN9C10X
, V4L2_FIELD_NONE
,
195 .sizeimage
= 352 * 288,
196 .colorspace
= V4L2_COLORSPACE_SRGB
,
200 static const __u8 probe_ov7630
[] = {0x08, 0x44};
202 static const __u8 initHv7131
[] = {
203 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
205 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
206 0x28, 0x1e, 0x60, 0x8a, 0x20,
207 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
209 static const __u8 hv7131_sensor_init
[][8] = {
210 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
211 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
212 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
213 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
214 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
216 static const __u8 initOv6650
[] = {
217 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
218 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
220 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
222 static const __u8 ov6650_sensor_init
[][8] =
224 /* Bright, contrast, etc are set througth SCBB interface.
225 * AVCAP on win2 do not send any data on this controls. */
226 /* Anyway, some registers appears to alter bright and constrat */
229 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
230 /* Set clock register 0x11 low nibble is clock divider */
231 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
232 /* Next some unknown stuff */
233 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
234 /* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
235 * THIS SET GREEN SCREEN
236 * (pixels could be innverted in decode kind of "brg",
237 * but blue wont be there. Avoid this data ... */
238 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
239 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
240 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
241 /* Enable rgb brightness control */
242 {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
243 /* HDG: Note windows uses the line below, which sets both register 0x60
244 and 0x61 I believe these registers of the ov6650 are identical as
245 those of the ov7630, because if this is true the windows settings
246 add a bit additional red gain and a lot additional blue gain, which
247 matches my findings that the windows settings make blue much too
248 blue and red a little too red.
249 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
250 /* Some more unknown stuff */
251 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
252 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
255 static const __u8 initOv7630
[] = {
256 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
257 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
258 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
259 0x28, 0x1e, /* H & V sizes r15 .. r16 */
260 0x68, COMP1
, MCK_INIT1
, /* r17 .. r19 */
261 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
263 static const __u8 initOv7630_3
[] = {
264 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
265 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
266 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
267 0x28, 0x1e, /* H & V sizes r15 .. r16 */
268 0x68, 0x8f, MCK_INIT1
, /* r17 .. r19 */
269 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
270 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
271 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
273 static const __u8 ov7630_sensor_init_com
[][8] = {
274 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
275 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
276 /* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
277 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
278 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
279 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
280 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
281 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
282 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
283 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
284 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
285 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
286 /* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
287 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
288 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
289 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
290 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
291 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
292 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
294 static const __u8 ov7630_sensor_init
[][8] = {
295 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
296 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
297 {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
298 {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
299 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
301 static const __u8 ov7630_sensor_init_3
[][8] = {
302 {0xa0, 0x21, 0x2a, 0xa0, 0x00, 0x00, 0x00, 0x10},
303 {0xa0, 0x21, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x10},
306 static const __u8 initPas106
[] = {
307 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
310 0x16, 0x12, 0x28, COMP1
, MCK_INIT1
,
311 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
313 /* compression 0x86 mckinit1 0x2b */
314 static const __u8 pas106_data
[][2] = {
315 {0x02, 0x04}, /* Pixel Clock Divider 6 */
316 {0x03, 0x13}, /* Frame Time MSB */
317 /* {0x03, 0x12}, * Frame Time MSB */
318 {0x04, 0x06}, /* Frame Time LSB */
319 /* {0x04, 0x05}, * Frame Time LSB */
320 {0x05, 0x65}, /* Shutter Time Line Offset */
321 /* {0x05, 0x6d}, * Shutter Time Line Offset */
322 /* {0x06, 0xb1}, * Shutter Time Pixel Offset */
323 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
324 {0x07, 0xc1}, /* Black Level Subtract Sign */
325 /* {0x07, 0x00}, * Black Level Subtract Sign */
326 {0x08, 0x06}, /* Black Level Subtract Level */
327 {0x08, 0x06}, /* Black Level Subtract Level */
328 /* {0x08, 0x01}, * Black Level Subtract Level */
329 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
330 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
331 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
332 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
333 {0x0d, 0x00}, /* Color GainH Pixel */
334 {0x0e, 0x0e}, /* Global Gain */
335 {0x0f, 0x00}, /* Contrast */
336 {0x10, 0x06}, /* H&V synchro polarity */
337 {0x11, 0x06}, /* ?default */
338 {0x12, 0x06}, /* DAC scale */
339 {0x14, 0x02}, /* ?default */
340 {0x13, 0x01}, /* Validate Settings */
342 static const __u8 initPas202
[] = {
343 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
345 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
346 0x28, 0x1e, 0x28, 0x89, 0x30,
347 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
349 static const __u8 pas202_sensor_init
[][8] = {
350 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
351 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
352 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
353 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
354 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
355 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
356 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
357 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
358 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
359 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
360 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
361 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
363 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
364 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
365 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
366 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
367 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
368 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
369 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
370 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
373 static const __u8 initTas5110
[] = {
374 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
376 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
377 0x16, 0x12, 0x60, 0x86, 0x2b,
378 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
380 static const __u8 tas5110_sensor_init
[][8] = {
381 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
382 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
383 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
386 static const __u8 initTas5130
[] = {
387 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
389 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
390 0x28, 0x1e, 0x60, COMP
, MCK_INIT
,
391 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
393 static const __u8 tas5130_sensor_init
[][8] = {
394 /* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
395 * shutter 0x47 short exposure? */
396 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
397 /* shutter 0x01 long exposure */
398 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
401 /* get one byte in gspca_dev->usb_buf */
402 static void reg_r(struct gspca_dev
*gspca_dev
,
405 usb_control_msg(gspca_dev
->dev
,
406 usb_rcvctrlpipe(gspca_dev
->dev
, 0),
408 USB_DIR_IN
| USB_TYPE_VENDOR
| USB_RECIP_INTERFACE
,
411 gspca_dev
->usb_buf
, 1,
415 static void reg_w(struct gspca_dev
*gspca_dev
,
420 #ifdef CONFIG_VIDEO_ADV_DEBUG
421 if (len
> sizeof gspca_dev
->usb_buf
) {
422 PDEBUG(D_ERR
|D_PACK
, "reg_w: buffer overflow");
426 memcpy(gspca_dev
->usb_buf
, buffer
, len
);
427 usb_control_msg(gspca_dev
->dev
,
428 usb_sndctrlpipe(gspca_dev
->dev
, 0),
430 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_INTERFACE
,
433 gspca_dev
->usb_buf
, len
,
437 static void reg_w_big(struct gspca_dev
*gspca_dev
,
444 tmpbuf
= kmalloc(len
, GFP_KERNEL
);
445 memcpy(tmpbuf
, buffer
, len
);
446 usb_control_msg(gspca_dev
->dev
,
447 usb_sndctrlpipe(gspca_dev
->dev
, 0),
449 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_INTERFACE
,
457 static int i2c_w(struct gspca_dev
*gspca_dev
, const __u8
*buffer
)
462 reg_w(gspca_dev
, 0x08, buffer
, 8);
465 reg_r(gspca_dev
, 0x08);
466 if (gspca_dev
->usb_buf
[0] & 0x04) {
467 if (gspca_dev
->usb_buf
[0] & 0x08)
475 static void i2c_w_vector(struct gspca_dev
*gspca_dev
,
476 const __u8 buffer
[][8], int len
)
479 reg_w(gspca_dev
, 0x08, *buffer
, 8);
487 static void setbrightness(struct gspca_dev
*gspca_dev
)
489 struct sd
*sd
= (struct sd
*) gspca_dev
;
492 switch (sd
->sensor
) {
494 case SENSOR_OV7630_3
:
495 case SENSOR_OV7630
: {
497 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
499 /* change reg 0x06 */
500 i2cOV
[1] = sd
->sensor_addr
;
501 i2cOV
[3] = sd
->brightness
;
502 if (i2c_w(gspca_dev
, i2cOV
) < 0)
506 case SENSOR_PAS106
: {
508 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
510 i2c1
[3] = sd
->brightness
>> 3;
512 if (i2c_w(gspca_dev
, i2c1
) < 0)
516 if (i2c_w(gspca_dev
, i2c1
) < 0)
520 case SENSOR_PAS202
: {
521 /* __u8 i2cpexpo1[] =
522 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
524 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
526 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
527 static __u8 i2cpdoit
[] =
528 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
530 /* change reg 0x10 */
531 i2cpexpo
[4] = 0xff - sd
->brightness
;
532 /* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
534 /* if(i2c_w(gspca_dev,i2cpdoit) < 0)
536 if (i2c_w(gspca_dev
, i2cpexpo
) < 0)
538 if (i2c_w(gspca_dev
, i2cpdoit
) < 0)
540 i2cp202
[3] = sd
->brightness
>> 3;
541 if (i2c_w(gspca_dev
, i2cp202
) < 0)
543 if (i2c_w(gspca_dev
, i2cpdoit
) < 0)
547 case SENSOR_TAS5130CXX
: {
549 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
551 value
= 0xff - sd
->brightness
;
553 PDEBUG(D_CONF
, "brightness %d : %d", value
, i2c
[4]);
554 if (i2c_w(gspca_dev
, i2c
) < 0)
559 /* FIXME figure out howto control brightness on TAS5110 */
564 PDEBUG(D_ERR
, "i2c error brightness");
567 static void setsensorgain(struct gspca_dev
*gspca_dev
)
569 struct sd
*sd
= (struct sd
*) gspca_dev
;
570 unsigned char gain
= sd
->gain
;
572 switch (sd
->sensor
) {
574 case SENSOR_TAS5110
: {
576 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
579 if (i2c_w(gspca_dev
, i2c
) < 0)
587 case SENSOR_OV7630_3
: {
588 __u8 i2c
[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
590 i2c
[1] = sd
->sensor_addr
;
592 if (i2c_w(gspca_dev
, i2c
) < 0)
599 PDEBUG(D_ERR
, "i2c error gain");
602 static void setgain(struct gspca_dev
*gspca_dev
)
604 struct sd
*sd
= (struct sd
*) gspca_dev
;
608 gain
= sd
->gain
>> 4;
610 /* red and blue gain */
611 rgb_value
= gain
<< 4 | gain
;
612 reg_w(gspca_dev
, 0x10, &rgb_value
, 1);
615 reg_w(gspca_dev
, 0x11, &rgb_value
, 1);
617 if (sd
->sensor_has_gain
)
618 setsensorgain(gspca_dev
);
621 static void setexposure(struct gspca_dev
*gspca_dev
)
623 struct sd
*sd
= (struct sd
*) gspca_dev
;
625 switch (sd
->sensor
) {
626 case SENSOR_TAS5110
: {
629 /* register 19's high nibble contains the sn9c10x clock divider
630 The high nibble configures the no fps according to the
631 formula: 60 / high_nibble. With a maximum of 30 fps */
632 reg
= 120 * sd
->exposure
/ 1000;
637 reg
= (reg
<< 4) | 0x0b;
638 reg_w(gspca_dev
, 0x19, ®
, 1);
642 case SENSOR_OV7630_3
: {
643 /* The ov6650 / ov7630 have 2 registers which both influence
644 exposure, register 11, whose low nibble sets the nr off fps
645 according to: fps = 30 / (low_nibble + 1)
647 The fps configures the maximum exposure setting, but it is
648 possible to use less exposure then what the fps maximum
649 allows by setting register 10. register 10 configures the
650 actual exposure as quotient of the full exposure, with 0
651 being no exposure at all (not very usefull) and reg10_max
652 being max exposure possible at that framerate.
654 The code maps our 0 - 510 ms exposure ctrl to these 2
655 registers, trying to keep fps as high as possible.
657 __u8 i2c
[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
659 /* ov6645 datasheet says reg10_max is 9a, but that uses
660 tline * 2 * reg10 as formula for calculating texpo, the
661 ov6650 probably uses the same formula as the 7730 which uses
662 tline * 4 * reg10, which explains why the reg10max we've
663 found experimentally for the ov6650 is exactly half that of
664 the ov6645. The ov7630 datasheet says the max is 0x41. */
665 const int reg10_max
= (sd
->sensor
== SENSOR_OV6650
)
668 reg11
= (60 * sd
->exposure
+ 999) / 1000;
674 /* frame exposure time in ms = 1000 * reg11 / 30 ->
675 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
676 reg10
= (sd
->exposure
* 60 * reg10_max
) / (1000 * reg11
);
678 /* Don't allow this to get below 10 when using autogain, the
679 steps become very large (relatively) when below 10 causing
680 the image to oscilate from much too dark, to much too bright
682 if (sd
->autogain
&& reg10
< 10)
684 else if (reg10
> reg10_max
)
687 /* Write reg 10 and reg11 low nibble */
688 i2c
[1] = sd
->sensor_addr
;
691 if (sd
->sensor
== SENSOR_OV7630_3
) {
692 __u8 reg76
= reg10
& 0x03;
693 __u8 i2c_reg76
[] = {0xa0, 0x21, 0x76, 0x00,
694 0x00, 0x00, 0x00, 0x10};
696 i2c_reg76
[3] = reg76
;
697 if (i2c_w(gspca_dev
, i2c_reg76
) < 0)
698 PDEBUG(D_ERR
, "i2c error exposure");
700 if (i2c_w(gspca_dev
, i2c
) < 0)
701 PDEBUG(D_ERR
, "i2c error exposure");
707 static void setfreq(struct gspca_dev
*gspca_dev
)
709 struct sd
*sd
= (struct sd
*) gspca_dev
;
711 switch (sd
->sensor
) {
713 case SENSOR_OV7630_3
: {
714 /* Framerate adjust register for artificial light 50 hz flicker
715 compensation, identical to ov6630 0x2b register, see ov6630
717 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
718 __u8 i2c
[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
721 /* case 0: * no filter*/
722 /* case 2: * 60 hz */
726 i2c
[3] = (sd
->sensor
== SENSOR_OV6650
)
730 i2c
[1] = sd
->sensor_addr
;
731 if (i2c_w(gspca_dev
, i2c
) < 0)
732 PDEBUG(D_ERR
, "i2c error setfreq");
739 static void do_autogain(struct gspca_dev
*gspca_dev
)
741 struct sd
*sd
= (struct sd
*) gspca_dev
;
742 int avg_lum
= atomic_read(&sd
->avg_lum
);
747 if (sd
->autogain_ignore_frames
> 0)
748 sd
->autogain_ignore_frames
--;
749 else if (gspca_auto_gain_n_exposure(gspca_dev
, avg_lum
,
750 sd
->brightness
* DESIRED_AVG_LUM
/ 127,
751 AUTOGAIN_DEADZONE
, GAIN_KNEE
, EXPOSURE_KNEE
)) {
752 PDEBUG(D_FRAM
, "autogain: gain changed: gain: %d expo: %d\n",
753 (int)sd
->gain
, (int)sd
->exposure
);
754 sd
->autogain_ignore_frames
= AUTOGAIN_IGNORE_FRAMES
;
758 /* this function is called at probe time */
759 static int sd_config(struct gspca_dev
*gspca_dev
,
760 const struct usb_device_id
*id
)
762 struct sd
*sd
= (struct sd
*) gspca_dev
;
767 /* nctrls depends upon the sensor, so we use a per cam copy */
768 memcpy(&sd
->sd_desc
, gspca_dev
->sd_desc
, sizeof(struct sd_desc
));
769 gspca_dev
->sd_desc
= &sd
->sd_desc
;
771 sd
->fr_h_sz
= 12; /* default size of the frame header */
772 sd
->sd_desc
.nctrls
= 2; /* default nb of ctrls */
773 sd
->autogain
= AUTOGAIN_DEF
; /* default is autogain active */
776 product
= id
->idProduct
;
777 /* switch (id->idVendor) { */
778 /* case 0x0c45: * Sonix */
780 case 0x6001: /* SN9C102 */
781 case 0x6005: /* SN9C101 */
782 case 0x6007: /* SN9C101 */
783 sd
->sensor
= SENSOR_TAS5110
;
784 sd
->sensor_has_gain
= 1;
785 sd
->sd_desc
.nctrls
= 4;
786 sd
->sd_desc
.dq_callback
= do_autogain
;
789 case 0x6009: /* SN9C101 */
790 case 0x600d: /* SN9C101 */
791 case 0x6029: /* SN9C101 */
792 sd
->sensor
= SENSOR_PAS106
;
795 case 0x6011: /* SN9C101 - SN9C101G */
796 sd
->sensor
= SENSOR_OV6650
;
797 sd
->sensor_has_gain
= 1;
798 sd
->sensor_addr
= 0x60;
799 sd
->sd_desc
.nctrls
= 5;
800 sd
->sd_desc
.dq_callback
= do_autogain
;
803 case 0x6019: /* SN9C101 */
804 case 0x602c: /* SN9C102 */
805 case 0x602e: /* SN9C102 */
806 sd
->sensor
= SENSOR_OV7630
;
807 sd
->sensor_addr
= 0x21;
809 case 0x60b0: /* SN9C103 */
810 sd
->sensor
= SENSOR_OV7630_3
;
811 sd
->sensor_addr
= 0x21;
812 sd
->fr_h_sz
= 18; /* size of frame header */
813 sd
->sensor_has_gain
= 1;
814 sd
->sd_desc
.nctrls
= 5;
815 sd
->sd_desc
.dq_callback
= do_autogain
;
818 case 0x6024: /* SN9C102 */
819 case 0x6025: /* SN9C102 */
820 sd
->sensor
= SENSOR_TAS5130CXX
;
822 case 0x6028: /* SN9C102 */
823 sd
->sensor
= SENSOR_PAS202
;
825 case 0x602d: /* SN9C102 */
826 sd
->sensor
= SENSOR_HV7131R
;
828 case 0x60af: /* SN9C103 */
829 sd
->sensor
= SENSOR_PAS202
;
830 sd
->fr_h_sz
= 18; /* size of frame header (?) */
836 cam
= &gspca_dev
->cam
;
837 cam
->dev_name
= (char *) id
->driver_info
;
840 cam
->cam_mode
= vga_mode
;
841 cam
->nmodes
= ARRAY_SIZE(vga_mode
);
842 if (sd
->sensor
== SENSOR_OV7630_3
) {
843 /* We only have 320x240 & 640x480 */
848 cam
->cam_mode
= sif_mode
;
849 cam
->nmodes
= ARRAY_SIZE(sif_mode
);
851 sd
->brightness
= BRIGHTNESS_DEF
;
853 sd
->exposure
= EXPOSURE_DEF
;
854 if (sd
->sensor
== SENSOR_OV7630_3
) /* jfm: from win trace */
855 reg_w(gspca_dev
, 0x01, probe_ov7630
, sizeof probe_ov7630
);
859 /* this function is called at open time */
860 static int sd_open(struct gspca_dev
*gspca_dev
)
862 reg_r(gspca_dev
, 0x00);
863 if (gspca_dev
->usb_buf
[0] != 0x10)
868 static void pas106_i2cinit(struct gspca_dev
*gspca_dev
)
872 __u8 i2c1
[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
874 i
= ARRAY_SIZE(pas106_data
);
875 data
= pas106_data
[0];
877 memcpy(&i2c1
[2], data
, 2);
878 /* copy 2 bytes from the template */
879 if (i2c_w(gspca_dev
, i2c1
) < 0)
880 PDEBUG(D_ERR
, "i2c error pas106");
885 /* -- start the camera -- */
886 static void sd_start(struct gspca_dev
*gspca_dev
)
888 struct sd
*sd
= (struct sd
*) gspca_dev
;
894 mode
= gspca_dev
->cam
.cam_mode
[(int) gspca_dev
->curr_mode
].priv
;
895 switch (sd
->sensor
) {
897 sn9c10x
= initHv7131
;
899 reg17_19
[1] = (mode
<< 4) | 0x8a;
903 sn9c10x
= initOv6650
;
905 reg17_19
[1] = (mode
<< 4) | 0x8b;
909 sn9c10x
= initOv7630
;
911 reg17_19
[1] = (mode
<< 4) | COMP2
;
912 reg17_19
[2] = MCK_INIT1
;
914 case SENSOR_OV7630_3
:
915 sn9c10x
= initOv7630_3
;
917 reg17_19
[1] = (mode
<< 4) | COMP2
;
918 reg17_19
[2] = MCK_INIT1
;
921 sn9c10x
= initPas106
;
922 reg17_19
[0] = 0x24; /* 0x28 */
923 reg17_19
[1] = (mode
<< 4) | COMP1
;
924 reg17_19
[2] = MCK_INIT1
;
927 sn9c10x
= initPas202
;
928 reg17_19
[0] = mode
? 0x24 : 0x20;
929 reg17_19
[1] = (mode
<< 4) | 0x89;
933 sn9c10x
= initTas5110
;
935 reg17_19
[1] = (mode
<< 4) | 0x86;
936 reg17_19
[2] = 0x2b; /* 0xf3; */
939 /* case SENSOR_TAS5130CXX: */
940 sn9c10x
= initTas5130
;
942 reg17_19
[1] = (mode
<< 4) | COMP
;
943 reg17_19
[2] = mode
? 0x23 : 0x43;
946 switch (sd
->sensor
) {
950 l
= sizeof initOv7630
;
952 case SENSOR_OV7630_3
:
955 l
= sizeof initOv7630_3
;
959 reg17
= sn9c10x
[0x17 - 1];
964 /* reg 0x01 bit 2 video transfert on */
965 reg_w(gspca_dev
, 0x01, ®01
, 1);
966 /* reg 0x17 SensorClk enable inv Clk 0x60 */
967 reg_w(gspca_dev
, 0x17, ®17
, 1);
968 /*fixme: for ov7630 102
969 reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
970 /* Set the registers from the template */
971 reg_w_big(gspca_dev
, 0x01, sn9c10x
, l
);
972 switch (sd
->sensor
) {
974 i2c_w_vector(gspca_dev
, hv7131_sensor_init
,
975 sizeof hv7131_sensor_init
);
978 i2c_w_vector(gspca_dev
, ov6650_sensor_init
,
979 sizeof ov6650_sensor_init
);
982 i2c_w_vector(gspca_dev
, ov7630_sensor_init_com
,
983 sizeof ov7630_sensor_init_com
);
985 i2c_w_vector(gspca_dev
, ov7630_sensor_init
,
986 sizeof ov7630_sensor_init
);
988 case SENSOR_OV7630_3
:
989 i2c_w_vector(gspca_dev
, ov7630_sensor_init_com
,
990 sizeof ov7630_sensor_init_com
);
992 i2c_w(gspca_dev
, ov7630_sensor_init_3
[mode
]);
995 pas106_i2cinit(gspca_dev
);
998 i2c_w_vector(gspca_dev
, pas202_sensor_init
,
999 sizeof pas202_sensor_init
);
1001 case SENSOR_TAS5110
:
1002 i2c_w_vector(gspca_dev
, tas5110_sensor_init
,
1003 sizeof tas5110_sensor_init
);
1006 /* case SENSOR_TAS5130CXX: */
1007 i2c_w_vector(gspca_dev
, tas5130_sensor_init
,
1008 sizeof tas5130_sensor_init
);
1011 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
1012 reg_w(gspca_dev
, 0x15, &sn9c10x
[0x15 - 1], 2);
1013 /* compression register */
1014 reg_w(gspca_dev
, 0x18, ®17_19
[1], 1);
1016 reg_w(gspca_dev
, 0x12, &sn9c10x
[0x12 - 1], 1);
1018 reg_w(gspca_dev
, 0x13, &sn9c10x
[0x13 - 1], 1);
1019 /* reset 0x17 SensorClk enable inv Clk 0x60 */
1020 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
1021 reg_w(gspca_dev
, 0x17, ®17_19
[0], 1);
1022 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
1023 reg_w(gspca_dev
, 0x19, ®17_19
[2], 1);
1024 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
1025 reg_w(gspca_dev
, 0x1c, &sn9c10x
[0x1c - 1], 4);
1026 /* Enable video transfert */
1027 reg_w(gspca_dev
, 0x01, &sn9c10x
[0], 1);
1029 reg_w(gspca_dev
, 0x18, ®17_19
[1], 2);
1033 setbrightness(gspca_dev
);
1034 setexposure(gspca_dev
);
1037 sd
->autogain_ignore_frames
= 0;
1038 atomic_set(&sd
->avg_lum
, -1);
1041 static void sd_stopN(struct gspca_dev
*gspca_dev
)
1045 ByteSend
= 0x09; /* 0X00 */
1046 reg_w(gspca_dev
, 0x01, &ByteSend
, 1);
1049 static void sd_stop0(struct gspca_dev
*gspca_dev
)
1053 static void sd_close(struct gspca_dev
*gspca_dev
)
1057 static void sd_pkt_scan(struct gspca_dev
*gspca_dev
,
1058 struct gspca_frame
*frame
, /* target */
1059 unsigned char *data
, /* isoc packet */
1060 int len
) /* iso packet length */
1063 struct sd
*sd
= (struct sd
*) gspca_dev
;
1065 /* frames start with:
1066 * ff ff 00 c4 c4 96 synchro
1068 * xx (frame sequence / size / compression)
1069 * (xx) (idem - extra byte for sn9c103)
1070 * ll mm brightness sum inside auto exposure
1071 * ll mm brightness sum outside auto exposure
1072 * (xx xx xx xx xx) audio values for snc103
1074 if (len
> 6 && len
< 24) {
1075 for (i
= 0; i
< len
- 6; i
++) {
1076 if (data
[0 + i
] == 0xff
1077 && data
[1 + i
] == 0xff
1078 && data
[2 + i
] == 0x00
1079 && data
[3 + i
] == 0xc4
1080 && data
[4 + i
] == 0xc4
1081 && data
[5 + i
] == 0x96) { /* start of frame */
1082 frame
= gspca_frame_add(gspca_dev
, LAST_PACKET
,
1084 if (len
- i
< sd
->fr_h_sz
) {
1085 atomic_set(&sd
->avg_lum
, -1);
1086 PDEBUG(D_STREAM
, "packet too short to"
1087 " get avg brightness");
1088 } else if (sd
->fr_h_sz
== 12) {
1089 atomic_set(&sd
->avg_lum
,
1091 (data
[i
+ 9] << 8));
1093 atomic_set(&sd
->avg_lum
,
1095 (data
[i
+ 10] << 8));
1097 data
+= i
+ sd
->fr_h_sz
;
1098 len
-= i
+ sd
->fr_h_sz
;
1099 gspca_frame_add(gspca_dev
, FIRST_PACKET
,
1105 gspca_frame_add(gspca_dev
, INTER_PACKET
,
1109 static int sd_setbrightness(struct gspca_dev
*gspca_dev
, __s32 val
)
1111 struct sd
*sd
= (struct sd
*) gspca_dev
;
1113 sd
->brightness
= val
;
1114 if (gspca_dev
->streaming
)
1115 setbrightness(gspca_dev
);
1119 static int sd_getbrightness(struct gspca_dev
*gspca_dev
, __s32
*val
)
1121 struct sd
*sd
= (struct sd
*) gspca_dev
;
1123 *val
= sd
->brightness
;
1127 static int sd_setgain(struct gspca_dev
*gspca_dev
, __s32 val
)
1129 struct sd
*sd
= (struct sd
*) gspca_dev
;
1132 if (gspca_dev
->streaming
)
1137 static int sd_getgain(struct gspca_dev
*gspca_dev
, __s32
*val
)
1139 struct sd
*sd
= (struct sd
*) gspca_dev
;
1145 static int sd_setexposure(struct gspca_dev
*gspca_dev
, __s32 val
)
1147 struct sd
*sd
= (struct sd
*) gspca_dev
;
1150 if (gspca_dev
->streaming
)
1151 setexposure(gspca_dev
);
1155 static int sd_getexposure(struct gspca_dev
*gspca_dev
, __s32
*val
)
1157 struct sd
*sd
= (struct sd
*) gspca_dev
;
1159 *val
= sd
->exposure
;
1163 static int sd_setautogain(struct gspca_dev
*gspca_dev
, __s32 val
)
1165 struct sd
*sd
= (struct sd
*) gspca_dev
;
1168 /* when switching to autogain set defaults to make sure
1169 we are on a valid point of the autogain gain /
1170 exposure knee graph, and give this change time to
1171 take effect before doing autogain. */
1173 sd
->exposure
= EXPOSURE_DEF
;
1174 sd
->gain
= GAIN_DEF
;
1175 if (gspca_dev
->streaming
) {
1176 sd
->autogain_ignore_frames
= AUTOGAIN_IGNORE_FRAMES
;
1177 setexposure(gspca_dev
);
1185 static int sd_getautogain(struct gspca_dev
*gspca_dev
, __s32
*val
)
1187 struct sd
*sd
= (struct sd
*) gspca_dev
;
1189 *val
= sd
->autogain
;
1193 static int sd_setfreq(struct gspca_dev
*gspca_dev
, __s32 val
)
1195 struct sd
*sd
= (struct sd
*) gspca_dev
;
1198 if (gspca_dev
->streaming
)
1203 static int sd_getfreq(struct gspca_dev
*gspca_dev
, __s32
*val
)
1205 struct sd
*sd
= (struct sd
*) gspca_dev
;
1211 static int sd_querymenu(struct gspca_dev
*gspca_dev
,
1212 struct v4l2_querymenu
*menu
)
1215 case V4L2_CID_POWER_LINE_FREQUENCY
:
1216 switch (menu
->index
) {
1217 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1218 strcpy((char *) menu
->name
, "NoFliker");
1220 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1221 strcpy((char *) menu
->name
, "50 Hz");
1223 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1224 strcpy((char *) menu
->name
, "60 Hz");
1232 /* sub-driver description */
1233 static const struct sd_desc sd_desc
= {
1234 .name
= MODULE_NAME
,
1236 .nctrls
= ARRAY_SIZE(sd_ctrls
),
1237 .config
= sd_config
,
1243 .pkt_scan
= sd_pkt_scan
,
1244 .querymenu
= sd_querymenu
,
1247 /* -- module initialisation -- */
1248 #define DVNM(name) .driver_info = (kernel_ulong_t) name
1249 static __devinitdata
struct usb_device_id device_table
[] = {
1250 #ifndef CONFIG_USB_SN9C102
1251 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1252 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1253 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1254 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1255 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
1256 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
1257 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1258 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1259 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1260 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1261 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1262 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1263 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1264 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1265 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1266 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
1270 MODULE_DEVICE_TABLE(usb
, device_table
);
1272 /* -- device connect -- */
1273 static int sd_probe(struct usb_interface
*intf
,
1274 const struct usb_device_id
*id
)
1276 return gspca_dev_probe(intf
, id
, &sd_desc
, sizeof(struct sd
),
1280 static struct usb_driver sd_driver
= {
1281 .name
= MODULE_NAME
,
1282 .id_table
= device_table
,
1284 .disconnect
= gspca_disconnect
,
1287 /* -- module insert / remove -- */
1288 static int __init
sd_mod_init(void)
1290 if (usb_register(&sd_driver
) < 0)
1292 PDEBUG(D_PROBE
, "v%s registered", version
);
1295 static void __exit
sd_mod_exit(void)
1297 usb_deregister(&sd_driver
);
1298 PDEBUG(D_PROBE
, "deregistered");
1301 module_init(sd_mod_init
);
1302 module_exit(sd_mod_exit
);