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 /* Some documentation on known sonixb registers:
26 0x10 high nibble red gain low nibble blue gain
27 0x11 low nibble green gain
30 0x15 hsize (hsize = register-value * 16)
31 0x16 vsize (vsize = register-value * 16)
32 0x17 bit 0 toggle compression quality (according to sn9c102 driver)
33 0x18 bit 7 enables compression, bit 4-5 set image down scaling:
34 00 scale 1, 01 scale 1/2, 10, scale 1/4
35 0x19 high-nibble is sensor clock divider, changes exposure on sensors which
36 use a clock generated by the bridge. Some sensors have their own clock.
37 0x1c auto_exposure area (for avg_lum) startx (startx = register-value * 32)
38 0x1d auto_exposure area (for avg_lum) starty (starty = register-value * 32)
39 0x1e auto_exposure area (for avg_lum) stopx (hsize = (0x1e - 0x1c) * 32)
40 0x1f auto_exposure area (for avg_lum) stopy (vsize = (0x1f - 0x1d) * 32)
43 #define MODULE_NAME "sonixb"
47 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
48 MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
49 MODULE_LICENSE("GPL");
51 /* specific webcam descriptor */
53 struct gspca_dev gspca_dev; /* !! must be the first item */
58 unsigned char exposure;
59 unsigned char brightness;
60 unsigned char autogain;
61 unsigned char autogain_ignore_frames;
62 unsigned char frames_to_drop;
63 unsigned char freq; /* light freq filter setting */
65 __u8 bridge; /* Type of bridge */
67 #define BRIDGE_102 0 /* We make no difference between 101 and 102 */
70 __u8 sensor; /* Type of image sensor chip */
71 #define SENSOR_HV7131R 0
72 #define SENSOR_OV6650 1
73 #define SENSOR_OV7630 2
74 #define SENSOR_PAS106 3
75 #define SENSOR_PAS202 4
76 #define SENSOR_TAS5110 5
77 #define SENSOR_TAS5130CXX 6
81 typedef const __u8 sensor_init_t[8];
84 const __u8 *bridge_init[2];
85 int bridge_init_size[2];
86 sensor_init_t *sensor_init;
88 sensor_init_t *sensor_bridge_init[2];
89 int sensor_bridge_init_size[2];
95 /* sensor_data flags */
96 #define F_GAIN 0x01 /* has gain */
97 #define F_SIF 0x02 /* sif or vga */
99 /* priv field of struct v4l2_pix_format flags (do not use low nibble!) */
100 #define MODE_RAW 0x10 /* raw bayer mode */
101 #define MODE_REDUCED_SIF 0x20 /* vga mode (320x240 / 160x120) on sif cam */
103 /* ctrl_dis helper macros */
104 #define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX))
105 #define NO_FREQ (1 << FREQ_IDX)
106 #define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX)
109 #define COMP 0xc7 /* 0x87 //0x07 */
110 #define COMP1 0xc9 /* 0x89 //0x09 */
112 #define MCK_INIT 0x63
113 #define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
117 #define SENS(bridge_1, bridge_3, sensor, sensor_1, \
118 sensor_3, _flags, _ctrl_dis, _sensor_addr) \
120 .bridge_init = { bridge_1, bridge_3 }, \
121 .bridge_init_size = { sizeof(bridge_1), sizeof(bridge_3) }, \
122 .sensor_init = sensor, \
123 .sensor_init_size = sizeof(sensor), \
124 .sensor_bridge_init = { sensor_1, sensor_3,}, \
125 .sensor_bridge_init_size = { sizeof(sensor_1), sizeof(sensor_3)}, \
126 .flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \
129 /* We calculate the autogain at the end of the transfer of a frame, at this
130 moment a frame with the old settings is being transmitted, and a frame is
131 being captured with the old settings. So if we adjust the autogain we must
132 ignore atleast the 2 next frames for the new settings to come into effect
133 before doing any other adjustments */
134 #define AUTOGAIN_IGNORE_FRAMES 3
135 #define AUTOGAIN_DEADZONE 1000
136 #define DESIRED_AVG_LUM 7000
138 /* V4L2 controls supported by the driver */
139 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
140 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
141 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
142 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
143 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
144 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
145 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
146 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
147 static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
148 static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
150 static struct ctrl sd_ctrls[] = {
151 #define BRIGHTNESS_IDX 0
154 .id = V4L2_CID_BRIGHTNESS,
155 .type = V4L2_CTRL_TYPE_INTEGER,
156 .name = "Brightness",
160 #define BRIGHTNESS_DEF 127
161 .default_value = BRIGHTNESS_DEF,
163 .set = sd_setbrightness,
164 .get = sd_getbrightness,
170 .type = V4L2_CTRL_TYPE_INTEGER,
176 #define GAIN_KNEE 200
177 .default_value = GAIN_DEF,
182 #define EXPOSURE_IDX 2
185 .id = V4L2_CID_EXPOSURE,
186 .type = V4L2_CTRL_TYPE_INTEGER,
188 #define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
189 #define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
193 .default_value = EXPOSURE_DEF,
196 .set = sd_setexposure,
197 .get = sd_getexposure,
199 #define AUTOGAIN_IDX 3
202 .id = V4L2_CID_AUTOGAIN,
203 .type = V4L2_CTRL_TYPE_BOOLEAN,
204 .name = "Automatic Gain (and Exposure)",
208 #define AUTOGAIN_DEF 1
209 .default_value = AUTOGAIN_DEF,
212 .set = sd_setautogain,
213 .get = sd_getautogain,
218 .id = V4L2_CID_POWER_LINE_FREQUENCY,
219 .type = V4L2_CTRL_TYPE_MENU,
220 .name = "Light frequency filter",
222 .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
225 .default_value = FREQ_DEF,
232 static struct v4l2_pix_format vga_mode[] = {
233 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
235 .sizeimage = 160 * 120 * 5 / 4,
236 .colorspace = V4L2_COLORSPACE_SRGB,
237 .priv = 2 | MODE_RAW},
238 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
240 .sizeimage = 160 * 120 * 5 / 4,
241 .colorspace = V4L2_COLORSPACE_SRGB,
243 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
245 .sizeimage = 320 * 240 * 5 / 4,
246 .colorspace = V4L2_COLORSPACE_SRGB,
248 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
250 .sizeimage = 640 * 480 * 5 / 4,
251 .colorspace = V4L2_COLORSPACE_SRGB,
254 static struct v4l2_pix_format sif_mode[] = {
255 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
257 .sizeimage = 160 * 120,
258 .colorspace = V4L2_COLORSPACE_SRGB,
259 .priv = 1 | MODE_RAW | MODE_REDUCED_SIF},
260 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
262 .sizeimage = 160 * 120 * 5 / 4,
263 .colorspace = V4L2_COLORSPACE_SRGB,
264 .priv = 1 | MODE_REDUCED_SIF},
265 {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
267 .sizeimage = 176 * 144 * 5 / 4,
268 .colorspace = V4L2_COLORSPACE_SRGB,
269 .priv = 1 | MODE_RAW},
270 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
272 .sizeimage = 176 * 144 * 5 / 4,
273 .colorspace = V4L2_COLORSPACE_SRGB,
275 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
277 .sizeimage = 320 * 240 * 5 / 4,
278 .colorspace = V4L2_COLORSPACE_SRGB,
279 .priv = 0 | MODE_REDUCED_SIF},
280 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
282 .sizeimage = 352 * 288 * 5 / 4,
283 .colorspace = V4L2_COLORSPACE_SRGB,
287 static const __u8 initHv7131[] = {
288 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
291 0x28, 0x1e, 0x60, 0x8a, 0x20,
292 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
294 static const __u8 hv7131_sensor_init[][8] = {
295 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
296 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
297 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
298 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
299 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
301 static const __u8 initOv6650[] = {
302 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
303 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b,
305 0x10, 0x1d, 0x10, 0x02, 0x02, 0x09, 0x07
307 static const __u8 ov6650_sensor_init[][8] =
309 /* Bright, contrast, etc are set througth SCBB interface.
310 * AVCAP on win2 do not send any data on this controls. */
311 /* Anyway, some registers appears to alter bright and constrat */
314 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
315 /* Set clock register 0x11 low nibble is clock divider */
316 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
317 /* Next some unknown stuff */
318 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
319 /* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
320 * THIS SET GREEN SCREEN
321 * (pixels could be innverted in decode kind of "brg",
322 * but blue wont be there. Avoid this data ... */
323 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
324 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
325 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
326 /* Enable rgb brightness control */
327 {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
328 /* HDG: Note windows uses the line below, which sets both register 0x60
329 and 0x61 I believe these registers of the ov6650 are identical as
330 those of the ov7630, because if this is true the windows settings
331 add a bit additional red gain and a lot additional blue gain, which
332 matches my findings that the windows settings make blue much too
333 blue and red a little too red.
334 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
335 /* Some more unknown stuff */
336 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
337 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
340 static const __u8 initOv7630[] = {
341 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
342 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
343 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
344 0x28, 0x1e, /* H & V sizes r15 .. r16 */
345 0x68, COMP2, MCK_INIT1, /* r17 .. r19 */
346 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
348 static const __u8 initOv7630_3[] = {
349 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
350 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
351 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
352 0x28, 0x1e, /* H & V sizes r15 .. r16 */
353 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
354 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
355 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
356 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
358 static const __u8 ov7630_sensor_init[][8] = {
359 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
360 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
361 /* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
362 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
363 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
364 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
365 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
366 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
367 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
368 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
369 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
370 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
371 /* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
372 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
373 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
374 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
375 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
376 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
377 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
380 static const __u8 ov7630_sensor_init_3[][8] = {
381 {0xa0, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10},
384 static const __u8 initPas106[] = {
385 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
387 0x00, 0x00, 0x00, 0x04, 0x01, 0x00,
388 0x16, 0x12, 0x24, COMP1, MCK_INIT1,
389 0x18, 0x10, 0x02, 0x02, 0x09, 0x07
391 /* compression 0x86 mckinit1 0x2b */
392 static const __u8 pas106_sensor_init[][8] = {
393 /* Pixel Clock Divider 6 */
394 { 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 },
395 /* Frame Time MSB (also seen as 0x12) */
396 { 0xa1, 0x40, 0x03, 0x13, 0x00, 0x00, 0x00, 0x14 },
397 /* Frame Time LSB (also seen as 0x05) */
398 { 0xa1, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x14 },
399 /* Shutter Time Line Offset (also seen as 0x6d) */
400 { 0xa1, 0x40, 0x05, 0x65, 0x00, 0x00, 0x00, 0x14 },
401 /* Shutter Time Pixel Offset (also seen as 0xb1) */
402 { 0xa1, 0x40, 0x06, 0xcd, 0x00, 0x00, 0x00, 0x14 },
403 /* Black Level Subtract Sign (also seen 0x00) */
404 { 0xa1, 0x40, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x14 },
405 /* Black Level Subtract Level (also seen 0x01) */
406 { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
407 { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
408 /* Color Gain B Pixel 5 a */
409 { 0xa1, 0x40, 0x09, 0x05, 0x00, 0x00, 0x00, 0x14 },
410 /* Color Gain G1 Pixel 1 5 */
411 { 0xa1, 0x40, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x14 },
412 /* Color Gain G2 Pixel 1 0 5 */
413 { 0xa1, 0x40, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x14 },
414 /* Color Gain R Pixel 3 1 */
415 { 0xa1, 0x40, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x14 },
416 /* Color GainH Pixel */
417 { 0xa1, 0x40, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x14 },
419 { 0xa1, 0x40, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x14 },
421 { 0xa1, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14 },
422 /* H&V synchro polarity */
423 { 0xa1, 0x40, 0x10, 0x06, 0x00, 0x00, 0x00, 0x14 },
425 { 0xa1, 0x40, 0x11, 0x06, 0x00, 0x00, 0x00, 0x14 },
427 { 0xa1, 0x40, 0x12, 0x06, 0x00, 0x00, 0x00, 0x14 },
429 { 0xa1, 0x40, 0x14, 0x02, 0x00, 0x00, 0x00, 0x14 },
430 /* Validate Settings */
431 { 0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14 },
434 static const __u8 initPas202[] = {
435 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
437 0x00, 0x00, 0x00, 0x06, 0x03, 0x0a,
438 0x28, 0x1e, 0x28, 0x89, 0x20,
439 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
441 static const __u8 pas202_sensor_init[][8] = {
442 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
443 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
444 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
445 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
446 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
447 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
448 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
449 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
450 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
451 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
452 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
453 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
455 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
456 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
457 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
458 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
459 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
460 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
461 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
462 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
465 static const __u8 initTas5110[] = {
466 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
468 0x00, 0x01, 0x00, 0x45, 0x09, 0x0a,
469 0x16, 0x12, 0x60, 0x86, 0x2b,
470 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
472 static const __u8 tas5110_sensor_init[][8] = {
473 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
474 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
475 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
478 static const __u8 initTas5130[] = {
479 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
481 0x00, 0x01, 0x00, 0x68, 0x0c, 0x0a,
482 0x28, 0x1e, 0x60, COMP, MCK_INIT,
483 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
485 static const __u8 tas5130_sensor_init[][8] = {
486 /* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
487 * shutter 0x47 short exposure? */
488 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
489 /* shutter 0x01 long exposure */
490 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
493 struct sensor_data sensor_data[] = {
494 SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
495 SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
496 SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
498 SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ,
500 SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, 0,
502 SENS(initTas5110, NULL, tas5110_sensor_init, NULL, NULL, F_GAIN|F_SIF,
503 NO_BRIGHTNESS|NO_FREQ, 0),
504 SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ,
508 /* get one byte in gspca_dev->usb_buf */
509 static void reg_r(struct gspca_dev *gspca_dev,
512 usb_control_msg(gspca_dev->dev,
513 usb_rcvctrlpipe(gspca_dev->dev, 0),
515 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
518 gspca_dev->usb_buf, 1,
522 static void reg_w(struct gspca_dev *gspca_dev,
528 if (len > USB_BUF_SZ) {
529 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
533 memcpy(gspca_dev->usb_buf, buffer, len);
534 usb_control_msg(gspca_dev->dev,
535 usb_sndctrlpipe(gspca_dev->dev, 0),
537 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
540 gspca_dev->usb_buf, len,
544 static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
549 reg_w(gspca_dev, 0x08, buffer, 8);
552 reg_r(gspca_dev, 0x08);
553 if (gspca_dev->usb_buf[0] & 0x04) {
554 if (gspca_dev->usb_buf[0] & 0x08)
562 static void i2c_w_vector(struct gspca_dev *gspca_dev,
563 const __u8 buffer[][8], int len)
566 reg_w(gspca_dev, 0x08, *buffer, 8);
574 static void setbrightness(struct gspca_dev *gspca_dev)
576 struct sd *sd = (struct sd *) gspca_dev;
579 switch (sd->sensor) {
581 case SENSOR_OV7630: {
583 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
585 /* change reg 0x06 */
586 i2cOV[1] = sensor_data[sd->sensor].sensor_addr;
587 i2cOV[3] = sd->brightness;
588 if (i2c_w(gspca_dev, i2cOV) < 0)
592 case SENSOR_PAS106: {
594 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
596 i2c1[3] = sd->brightness >> 3;
598 if (i2c_w(gspca_dev, i2c1) < 0)
602 if (i2c_w(gspca_dev, i2c1) < 0)
606 case SENSOR_PAS202: {
607 /* __u8 i2cpexpo1[] =
608 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
610 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
612 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
613 static __u8 i2cpdoit[] =
614 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
616 /* change reg 0x10 */
617 i2cpexpo[4] = 0xff - sd->brightness;
618 /* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
620 /* if(i2c_w(gspca_dev,i2cpdoit) < 0)
622 if (i2c_w(gspca_dev, i2cpexpo) < 0)
624 if (i2c_w(gspca_dev, i2cpdoit) < 0)
626 i2cp202[3] = sd->brightness >> 3;
627 if (i2c_w(gspca_dev, i2cp202) < 0)
629 if (i2c_w(gspca_dev, i2cpdoit) < 0)
633 case SENSOR_TAS5130CXX: {
635 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
637 value = 0xff - sd->brightness;
639 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
640 if (i2c_w(gspca_dev, i2c) < 0)
647 PDEBUG(D_ERR, "i2c error brightness");
650 static void setsensorgain(struct gspca_dev *gspca_dev)
652 struct sd *sd = (struct sd *) gspca_dev;
653 unsigned char gain = sd->gain;
655 switch (sd->sensor) {
657 case SENSOR_TAS5110: {
659 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
662 if (i2c_w(gspca_dev, i2c) < 0)
670 case SENSOR_OV7630: {
671 __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
673 i2c[1] = sensor_data[sd->sensor].sensor_addr;
675 if (i2c_w(gspca_dev, i2c) < 0)
682 PDEBUG(D_ERR, "i2c error gain");
685 static void setgain(struct gspca_dev *gspca_dev)
687 struct sd *sd = (struct sd *) gspca_dev;
691 gain = sd->gain >> 4;
693 /* red and blue gain */
694 rgb_value = gain << 4 | gain;
695 reg_w(gspca_dev, 0x10, &rgb_value, 1);
698 reg_w(gspca_dev, 0x11, &rgb_value, 1);
700 if (sensor_data[sd->sensor].flags & F_GAIN)
701 setsensorgain(gspca_dev);
704 static void setexposure(struct gspca_dev *gspca_dev)
706 struct sd *sd = (struct sd *) gspca_dev;
708 switch (sd->sensor) {
709 case SENSOR_TAS5110: {
712 /* register 19's high nibble contains the sn9c10x clock divider
713 The high nibble configures the no fps according to the
714 formula: 60 / high_nibble. With a maximum of 30 fps */
715 reg = 120 * sd->exposure / 1000;
720 reg = (reg << 4) | 0x0b;
721 reg_w(gspca_dev, 0x19, ®, 1);
725 case SENSOR_OV7630: {
726 /* The ov6650 / ov7630 have 2 registers which both influence
727 exposure, register 11, whose low nibble sets the nr off fps
728 according to: fps = 30 / (low_nibble + 1)
730 The fps configures the maximum exposure setting, but it is
731 possible to use less exposure then what the fps maximum
732 allows by setting register 10. register 10 configures the
733 actual exposure as quotient of the full exposure, with 0
734 being no exposure at all (not very usefull) and reg10_max
735 being max exposure possible at that framerate.
737 The code maps our 0 - 510 ms exposure ctrl to these 2
738 registers, trying to keep fps as high as possible.
740 __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10};
741 int reg10, reg11, reg10_max;
743 /* ov6645 datasheet says reg10_max is 9a, but that uses
744 tline * 2 * reg10 as formula for calculating texpo, the
745 ov6650 probably uses the same formula as the 7730 which uses
746 tline * 4 * reg10, which explains why the reg10max we've
747 found experimentally for the ov6650 is exactly half that of
748 the ov6645. The ov7630 datasheet says the max is 0x41. */
749 if (sd->sensor == SENSOR_OV6650) {
751 i2c[4] = 0xc0; /* OV6650 needs non default vsync pol */
755 reg11 = (60 * sd->exposure + 999) / 1000;
761 /* In 640x480, if the reg11 has less than 3, the image is
762 unstable (not enough bandwidth). */
763 if (gspca_dev->width == 640 && reg11 < 3)
766 /* frame exposure time in ms = 1000 * reg11 / 30 ->
767 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
768 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
770 /* Don't allow this to get below 10 when using autogain, the
771 steps become very large (relatively) when below 10 causing
772 the image to oscilate from much too dark, to much too bright
774 if (sd->autogain && reg10 < 10)
776 else if (reg10 > reg10_max)
779 /* Write reg 10 and reg11 low nibble */
780 i2c[1] = sensor_data[sd->sensor].sensor_addr;
784 /* If register 11 didn't change, don't change it */
785 if (sd->reg11 == reg11 )
788 if (i2c_w(gspca_dev, i2c) == 0)
791 PDEBUG(D_ERR, "i2c error exposure");
797 static void setfreq(struct gspca_dev *gspca_dev)
799 struct sd *sd = (struct sd *) gspca_dev;
801 switch (sd->sensor) {
803 case SENSOR_OV7630: {
804 /* Framerate adjust register for artificial light 50 hz flicker
805 compensation, for the ov6650 this is identical to ov6630
806 0x2b register, see ov6630 datasheet.
807 0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */
808 __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
811 /* case 0: * no filter*/
812 /* case 2: * 60 hz */
816 i2c[3] = (sd->sensor == SENSOR_OV6650)
820 i2c[1] = sensor_data[sd->sensor].sensor_addr;
821 if (i2c_w(gspca_dev, i2c) < 0)
822 PDEBUG(D_ERR, "i2c error setfreq");
828 static void do_autogain(struct gspca_dev *gspca_dev)
830 struct sd *sd = (struct sd *) gspca_dev;
831 int avg_lum = atomic_read(&sd->avg_lum);
836 if (sd->autogain_ignore_frames > 0)
837 sd->autogain_ignore_frames--;
838 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
839 sd->brightness * DESIRED_AVG_LUM / 127,
840 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
841 PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
842 (int)sd->gain, (int)sd->exposure);
843 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
847 /* this function is called at probe time */
848 static int sd_config(struct gspca_dev *gspca_dev,
849 const struct usb_device_id *id)
851 struct sd *sd = (struct sd *) gspca_dev;
854 reg_r(gspca_dev, 0x00);
855 if (gspca_dev->usb_buf[0] != 0x10)
858 /* copy the webcam info from the device id */
859 sd->sensor = id->driver_info >> 8;
860 sd->bridge = id->driver_info & 0xff;
861 gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis;
863 cam = &gspca_dev->cam;
865 if (!(sensor_data[sd->sensor].flags & F_SIF)) {
866 cam->cam_mode = vga_mode;
867 cam->nmodes = ARRAY_SIZE(vga_mode);
869 cam->cam_mode = sif_mode;
870 cam->nmodes = ARRAY_SIZE(sif_mode);
872 sd->brightness = BRIGHTNESS_DEF;
874 sd->exposure = EXPOSURE_DEF;
875 if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
876 sd->autogain = 0; /* Disable do_autogain callback */
878 sd->autogain = AUTOGAIN_DEF;
884 /* this function is called at probe and resume time */
885 static int sd_init(struct gspca_dev *gspca_dev)
887 const __u8 stop = 0x09; /* Disable stream turn of LED */
889 reg_w(gspca_dev, 0x01, &stop, 1);
894 /* -- start the camera -- */
895 static void sd_start(struct gspca_dev *gspca_dev)
897 struct sd *sd = (struct sd *) gspca_dev;
898 struct cam *cam = &gspca_dev->cam;
903 mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07;
904 sn9c10x = sensor_data[sd->sensor].bridge_init[sd->bridge];
905 l = sensor_data[sd->sensor].bridge_init_size[sd->bridge];
906 memcpy(reg12_19, &sn9c10x[0x12 - 1], 8);
907 reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4);
908 /* Special cases where reg 17 and or 19 value depends on mode */
909 switch (sd->sensor) {
911 reg12_19[5] = mode ? 0x24 : 0x20;
913 case SENSOR_TAS5130CXX:
914 /* probably not mode specific at all most likely the upper
915 nibble of 0x19 is exposure (clock divider) just as with
916 the tas5110, we need someone to test this. */
917 reg12_19[7] = mode ? 0x23 : 0x43;
920 /* Disable compression when the raw bayer format has been selected */
921 if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW)
922 reg12_19[6] &= ~0x80;
924 /* Vga mode emulation on SIF sensor? */
925 if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) {
926 reg12_19[0] += 16; /* 0x12: hstart adjust */
927 reg12_19[1] += 24; /* 0x13: vstart adjust */
928 reg12_19[3] = 320 / 16; /* 0x15: hsize */
929 reg12_19[4] = 240 / 16; /* 0x16: vsize */
932 /* reg 0x01 bit 2 video transfert on */
933 reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1);
934 /* reg 0x17 SensorClk enable inv Clk 0x60 */
935 reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1);
936 /* Set the registers from the template */
937 reg_w(gspca_dev, 0x01, sn9c10x, l);
939 /* Init the sensor */
940 i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init,
941 sensor_data[sd->sensor].sensor_init_size);
942 if (sensor_data[sd->sensor].sensor_bridge_init[sd->bridge])
943 i2c_w_vector(gspca_dev,
944 sensor_data[sd->sensor].sensor_bridge_init[sd->bridge],
945 sensor_data[sd->sensor].sensor_bridge_init_size[
948 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
949 reg_w(gspca_dev, 0x15, ®12_19[3], 2);
950 /* compression register */
951 reg_w(gspca_dev, 0x18, ®12_19[6], 1);
953 reg_w(gspca_dev, 0x12, ®12_19[0], 1);
955 reg_w(gspca_dev, 0x13, ®12_19[1], 1);
956 /* reset 0x17 SensorClk enable inv Clk 0x60 */
957 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
958 reg_w(gspca_dev, 0x17, ®12_19[5], 1);
959 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
960 reg_w(gspca_dev, 0x19, ®12_19[7], 1);
961 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
962 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
963 /* Enable video transfert */
964 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
966 reg_w(gspca_dev, 0x18, ®12_19[6], 2);
972 setbrightness(gspca_dev);
973 setexposure(gspca_dev);
976 sd->frames_to_drop = 0;
977 sd->autogain_ignore_frames = 0;
978 atomic_set(&sd->avg_lum, -1);
981 static void sd_stopN(struct gspca_dev *gspca_dev)
986 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
987 struct gspca_frame *frame, /* target */
988 unsigned char *data, /* isoc packet */
989 int len) /* iso packet length */
992 struct sd *sd = (struct sd *) gspca_dev;
993 struct cam *cam = &gspca_dev->cam;
995 /* frames start with:
996 * ff ff 00 c4 c4 96 synchro
998 * xx (frame sequence / size / compression)
999 * (xx) (idem - extra byte for sn9c103)
1000 * ll mm brightness sum inside auto exposure
1001 * ll mm brightness sum outside auto exposure
1002 * (xx xx xx xx xx) audio values for snc103
1004 if (len > 6 && len < 24) {
1005 for (i = 0; i < len - 6; i++) {
1006 if (data[0 + i] == 0xff
1007 && data[1 + i] == 0xff
1008 && data[2 + i] == 0x00
1009 && data[3 + i] == 0xc4
1010 && data[4 + i] == 0xc4
1011 && data[5 + i] == 0x96) { /* start of frame */
1013 int pkt_type = LAST_PACKET;
1014 int fr_h_sz = (sd->bridge == BRIDGE_103) ?
1017 if (len - i < fr_h_sz) {
1018 PDEBUG(D_STREAM, "packet too short to"
1019 " get avg brightness");
1020 } else if (sd->bridge == BRIDGE_103) {
1022 (data[i + 10] << 8);
1024 lum = data[i + 8] + (data[i + 9] << 8);
1026 /* When exposure changes midway a frame we
1027 get a lum of 0 in this case drop 2 frames
1028 as the frames directly after an exposure
1029 change have an unstable image. Sometimes lum
1030 *really* is 0 (cam used in low light with
1031 low exposure setting), so do not drop frames
1032 if the previous lum was 0 too. */
1033 if (lum == 0 && sd->prev_avg_lum != 0) {
1035 sd->frames_to_drop = 2;
1036 sd->prev_avg_lum = 0;
1038 sd->prev_avg_lum = lum;
1039 atomic_set(&sd->avg_lum, lum);
1041 if (sd->frames_to_drop) {
1042 sd->frames_to_drop--;
1043 pkt_type = DISCARD_PACKET;
1046 frame = gspca_frame_add(gspca_dev, pkt_type,
1048 data += i + fr_h_sz;
1050 gspca_frame_add(gspca_dev, FIRST_PACKET,
1057 if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
1058 /* In raw mode we sometimes get some garbage after the frame
1060 int used = frame->data_end - frame->data;
1061 int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
1063 if (used + len > size)
1067 gspca_frame_add(gspca_dev, INTER_PACKET,
1071 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1073 struct sd *sd = (struct sd *) gspca_dev;
1075 sd->brightness = val;
1076 if (gspca_dev->streaming)
1077 setbrightness(gspca_dev);
1081 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1083 struct sd *sd = (struct sd *) gspca_dev;
1085 *val = sd->brightness;
1089 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
1091 struct sd *sd = (struct sd *) gspca_dev;
1094 if (gspca_dev->streaming)
1099 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
1101 struct sd *sd = (struct sd *) gspca_dev;
1107 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1109 struct sd *sd = (struct sd *) gspca_dev;
1112 if (gspca_dev->streaming)
1113 setexposure(gspca_dev);
1117 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1119 struct sd *sd = (struct sd *) gspca_dev;
1121 *val = sd->exposure;
1125 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1127 struct sd *sd = (struct sd *) gspca_dev;
1130 /* when switching to autogain set defaults to make sure
1131 we are on a valid point of the autogain gain /
1132 exposure knee graph, and give this change time to
1133 take effect before doing autogain. */
1135 sd->exposure = EXPOSURE_DEF;
1136 sd->gain = GAIN_DEF;
1137 if (gspca_dev->streaming) {
1138 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1139 setexposure(gspca_dev);
1147 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1149 struct sd *sd = (struct sd *) gspca_dev;
1151 *val = sd->autogain;
1155 static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1157 struct sd *sd = (struct sd *) gspca_dev;
1160 if (gspca_dev->streaming)
1165 static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1167 struct sd *sd = (struct sd *) gspca_dev;
1173 static int sd_querymenu(struct gspca_dev *gspca_dev,
1174 struct v4l2_querymenu *menu)
1177 case V4L2_CID_POWER_LINE_FREQUENCY:
1178 switch (menu->index) {
1179 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1180 strcpy((char *) menu->name, "NoFliker");
1182 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1183 strcpy((char *) menu->name, "50 Hz");
1185 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1186 strcpy((char *) menu->name, "60 Hz");
1194 /* sub-driver description */
1195 static const struct sd_desc sd_desc = {
1196 .name = MODULE_NAME,
1198 .nctrls = ARRAY_SIZE(sd_ctrls),
1199 .config = sd_config,
1203 .pkt_scan = sd_pkt_scan,
1204 .querymenu = sd_querymenu,
1205 .dq_callback = do_autogain,
1208 /* -- module initialisation -- */
1209 #define SB(sensor, bridge) \
1210 .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge
1213 static __devinitdata struct usb_device_id device_table[] = {
1214 {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110, 102)}, /* TAS5110C1B */
1215 {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110, 101)}, /* TAS5110C1B */
1216 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
1217 {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110, 101)}, /* TAS5110D */
1218 {USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)},
1219 {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
1221 {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
1222 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
1223 {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
1224 {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
1225 {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
1226 {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
1227 {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
1228 {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
1230 {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
1231 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
1232 {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
1234 {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)},
1235 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
1236 {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)},
1238 {USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)},
1241 MODULE_DEVICE_TABLE(usb, device_table);
1243 /* -- device connect -- */
1244 static int sd_probe(struct usb_interface *intf,
1245 const struct usb_device_id *id)
1247 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1251 static struct usb_driver sd_driver = {
1252 .name = MODULE_NAME,
1253 .id_table = device_table,
1255 .disconnect = gspca_disconnect,
1257 .suspend = gspca_suspend,
1258 .resume = gspca_resume,
1262 /* -- module insert / remove -- */
1263 static int __init sd_mod_init(void)
1265 if (usb_register(&sd_driver) < 0)
1267 PDEBUG(D_PROBE, "registered");
1270 static void __exit sd_mod_exit(void)
1272 usb_deregister(&sd_driver);
1273 PDEBUG(D_PROBE, "deregistered");
1276 module_init(sd_mod_init);
1277 module_exit(sd_mod_exit);