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 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
28 MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
29 MODULE_LICENSE("GPL");
31 /* specific webcam descriptor */
33 struct gspca_dev gspca_dev; /* !! must be the first item */
35 struct sd_desc sd_desc; /* our nctrls differ dependend upon the
36 sensor, so we use a per cam copy */
40 unsigned char exposure;
41 unsigned char brightness;
42 unsigned char autogain;
43 unsigned char autogain_ignore_frames;
44 unsigned char freq; /* light freq filter setting */
45 unsigned char saturation;
47 unsigned char contrast;
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);
92 static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val);
93 static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);
94 static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
95 static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
96 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
97 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
99 static struct ctrl sd_ctrls[] = {
102 .id = V4L2_CID_BRIGHTNESS,
103 .type = V4L2_CTRL_TYPE_INTEGER,
104 .name = "Brightness",
108 #define BRIGHTNESS_DEF 127
109 .default_value = BRIGHTNESS_DEF,
111 .set = sd_setbrightness,
112 .get = sd_getbrightness,
117 .type = V4L2_CTRL_TYPE_INTEGER,
123 #define GAIN_KNEE 200
124 .default_value = GAIN_DEF,
131 .id = V4L2_CID_EXPOSURE,
132 .type = V4L2_CTRL_TYPE_INTEGER,
134 #define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
135 #define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
139 .default_value = EXPOSURE_DEF,
142 .set = sd_setexposure,
143 .get = sd_getexposure,
147 .id = V4L2_CID_AUTOGAIN,
148 .type = V4L2_CTRL_TYPE_BOOLEAN,
149 .name = "Automatic Gain (and Exposure)",
153 #define AUTOGAIN_DEF 1
154 .default_value = AUTOGAIN_DEF,
157 .set = sd_setautogain,
158 .get = sd_getautogain,
162 .id = V4L2_CID_POWER_LINE_FREQUENCY,
163 .type = V4L2_CTRL_TYPE_MENU,
164 .name = "Light frequency filter",
166 .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
169 .default_value = FREQ_DEF,
176 .id = V4L2_CID_SATURATION,
177 .type = V4L2_CTRL_TYPE_INTEGER,
178 .name = "Saturation",
182 #define SATURATION_DEF 127
183 .default_value = SATURATION_DEF,
185 .set = sd_setsaturation,
186 .get = sd_getsaturation,
191 .type = V4L2_CTRL_TYPE_INTEGER,
197 .default_value = HUE_DEF,
204 .id = V4L2_CID_CONTRAST,
205 .type = V4L2_CTRL_TYPE_INTEGER,
210 #define CONTRAST_DEF 127
211 .default_value = CONTRAST_DEF,
213 .set = sd_setcontrast,
214 .get = sd_getcontrast,
218 static struct v4l2_pix_format vga_mode[] = {
219 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
221 .sizeimage = 160 * 120,
222 .colorspace = V4L2_COLORSPACE_SRGB,
224 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
226 .sizeimage = 320 * 240,
227 .colorspace = V4L2_COLORSPACE_SRGB,
229 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
231 .sizeimage = 640 * 480,
232 .colorspace = V4L2_COLORSPACE_SRGB,
235 static struct v4l2_pix_format sif_mode[] = {
236 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
238 .sizeimage = 176 * 144,
239 .colorspace = V4L2_COLORSPACE_SRGB,
241 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
243 .sizeimage = 352 * 288,
244 .colorspace = V4L2_COLORSPACE_SRGB,
248 static const __u8 probe_ov7630[] = {0x08, 0x44};
250 static const __u8 initHv7131[] = {
251 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
253 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
254 0x28, 0x1e, 0x60, 0x8a, 0x20,
255 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
257 static const __u8 hv7131_sensor_init[][8] = {
258 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
259 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
260 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
261 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
262 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
264 static const __u8 initOv6650[] = {
265 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
266 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
268 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
270 static const __u8 ov6650_sensor_init[][8] =
272 /* Bright, contrast, etc are set througth SCBB interface.
273 * AVCAP on win2 do not send any data on this controls. */
274 /* Anyway, some registers appears to alter bright and constrat */
277 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
278 /* Set clock register 0x11 low nibble is clock divider */
279 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
280 /* Next some unknown stuff */
281 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
282 /* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
283 * THIS SET GREEN SCREEN
284 * (pixels could be innverted in decode kind of "brg",
285 * but blue wont be there. Avoid this data ... */
286 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
287 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
288 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
289 /* Enable rgb brightness control */
290 {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
291 /* HDG: Note windows uses the line below, which sets both register 0x60
292 and 0x61 I believe these registers of the ov6650 are identical as
293 those of the ov7630, because if this is true the windows settings
294 add a bit additional red gain and a lot additional blue gain, which
295 matches my findings that the windows settings make blue much too
296 blue and red a little too red.
297 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
298 /* Some more unknown stuff */
299 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
300 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
303 static const __u8 initOv7630[] = {
304 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
305 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
306 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
307 0x28, 0x1e, /* H & V sizes r15 .. r16 */
308 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
309 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
311 static const __u8 initOv7630_3[] = {
312 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
313 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
314 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
315 0x28, 0x1e, /* H & V sizes r15 .. r16 */
316 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
317 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
318 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
319 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
321 static const __u8 ov7630_sensor_init_com[][8] = {
322 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
323 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
324 /* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
325 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
326 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
327 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
328 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
329 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
330 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
331 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
332 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
333 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
334 /* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
335 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
336 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
337 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
338 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
339 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
340 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
342 static const __u8 ov7630_sensor_init[][8] = {
343 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
344 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
345 {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
346 {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
347 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
349 static const __u8 ov7630_sensor_init_3[][8] = {
350 {0xa0, 0x21, 0x2a, 0xa0, 0x00, 0x00, 0x00, 0x10},
351 {0xa0, 0x21, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x10},
354 static const __u8 initPas106[] = {
355 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
358 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
359 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
361 /* compression 0x86 mckinit1 0x2b */
362 static const __u8 pas106_data[][2] = {
363 {0x02, 0x04}, /* Pixel Clock Divider 6 */
364 {0x03, 0x13}, /* Frame Time MSB */
365 /* {0x03, 0x12}, * Frame Time MSB */
366 {0x04, 0x06}, /* Frame Time LSB */
367 /* {0x04, 0x05}, * Frame Time LSB */
368 {0x05, 0x65}, /* Shutter Time Line Offset */
369 /* {0x05, 0x6d}, * Shutter Time Line Offset */
370 /* {0x06, 0xb1}, * Shutter Time Pixel Offset */
371 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
372 {0x07, 0xc1}, /* Black Level Subtract Sign */
373 /* {0x07, 0x00}, * Black Level Subtract Sign */
374 {0x08, 0x06}, /* Black Level Subtract Level */
375 {0x08, 0x06}, /* Black Level Subtract Level */
376 /* {0x08, 0x01}, * Black Level Subtract Level */
377 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
378 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
379 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
380 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
381 {0x0d, 0x00}, /* Color GainH Pixel */
382 {0x0e, 0x0e}, /* Global Gain */
383 {0x0f, 0x00}, /* Contrast */
384 {0x10, 0x06}, /* H&V synchro polarity */
385 {0x11, 0x06}, /* ?default */
386 {0x12, 0x06}, /* DAC scale */
387 {0x14, 0x02}, /* ?default */
388 {0x13, 0x01}, /* Validate Settings */
390 static const __u8 initPas202[] = {
391 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
393 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
394 0x28, 0x1e, 0x28, 0x89, 0x30,
395 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
397 static const __u8 pas202_sensor_init[][8] = {
398 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
399 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
400 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
401 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
402 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
403 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
404 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
405 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
406 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
407 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
408 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
409 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
411 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
412 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
413 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
414 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
415 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
416 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
417 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
418 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
421 static const __u8 initTas5110[] = {
422 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
424 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
425 0x16, 0x12, 0x60, 0x86, 0x2b,
426 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
428 static const __u8 tas5110_sensor_init[][8] = {
429 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
430 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
431 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
434 static const __u8 initTas5130[] = {
435 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
437 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
438 0x28, 0x1e, 0x60, COMP, MCK_INIT,
439 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
441 static const __u8 tas5130_sensor_init[][8] = {
442 /* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
443 * shutter 0x47 short exposure? */
444 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
445 /* shutter 0x01 long exposure */
446 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
449 /* get one byte in gspca_dev->usb_buf */
450 static void reg_r(struct gspca_dev *gspca_dev,
453 usb_control_msg(gspca_dev->dev,
454 usb_rcvctrlpipe(gspca_dev->dev, 0),
456 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
459 gspca_dev->usb_buf, 1,
463 static void reg_w(struct gspca_dev *gspca_dev,
468 #ifdef CONFIG_VIDEO_ADV_DEBUG
469 if (len > sizeof gspca_dev->usb_buf) {
470 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
474 memcpy(gspca_dev->usb_buf, buffer, len);
475 usb_control_msg(gspca_dev->dev,
476 usb_sndctrlpipe(gspca_dev->dev, 0),
478 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
481 gspca_dev->usb_buf, len,
485 static void reg_w_big(struct gspca_dev *gspca_dev,
492 tmpbuf = kmalloc(len, GFP_KERNEL);
493 memcpy(tmpbuf, buffer, len);
494 usb_control_msg(gspca_dev->dev,
495 usb_sndctrlpipe(gspca_dev->dev, 0),
497 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
505 static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
510 reg_w(gspca_dev, 0x08, buffer, 8);
513 reg_r(gspca_dev, 0x08);
514 if (gspca_dev->usb_buf[0] & 0x04) {
515 if (gspca_dev->usb_buf[0] & 0x08)
523 static void i2c_w_vector(struct gspca_dev *gspca_dev,
524 const __u8 buffer[][8], int len)
527 reg_w(gspca_dev, 0x08, *buffer, 8);
535 static void setbrightness(struct gspca_dev *gspca_dev)
537 struct sd *sd = (struct sd *) gspca_dev;
540 switch (sd->sensor) {
542 case SENSOR_OV7630_3:
543 case SENSOR_OV7630: {
545 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
547 /* change reg 0x06 */
548 i2cOV[1] = sd->sensor_addr;
549 i2cOV[3] = sd->brightness;
550 if (i2c_w(gspca_dev, i2cOV) < 0)
554 case SENSOR_PAS106: {
556 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
558 i2c1[3] = sd->brightness >> 3;
560 if (i2c_w(gspca_dev, i2c1) < 0)
564 if (i2c_w(gspca_dev, i2c1) < 0)
568 case SENSOR_PAS202: {
569 /* __u8 i2cpexpo1[] =
570 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
572 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
574 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
575 static __u8 i2cpdoit[] =
576 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
578 /* change reg 0x10 */
579 i2cpexpo[4] = 0xff - sd->brightness;
580 /* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
582 /* if(i2c_w(gspca_dev,i2cpdoit) < 0)
584 if (i2c_w(gspca_dev, i2cpexpo) < 0)
586 if (i2c_w(gspca_dev, i2cpdoit) < 0)
588 i2cp202[3] = sd->brightness >> 3;
589 if (i2c_w(gspca_dev, i2cp202) < 0)
591 if (i2c_w(gspca_dev, i2cpdoit) < 0)
595 case SENSOR_TAS5130CXX: {
597 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
599 value = 0xff - sd->brightness;
601 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
602 if (i2c_w(gspca_dev, i2c) < 0)
607 /* FIXME figure out howto control brightness on TAS5110 */
612 PDEBUG(D_ERR, "i2c error brightness");
615 static void setsensorgain(struct gspca_dev *gspca_dev)
617 struct sd *sd = (struct sd *) gspca_dev;
618 unsigned char gain = sd->gain;
620 switch (sd->sensor) {
622 case SENSOR_TAS5110: {
624 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
627 if (i2c_w(gspca_dev, i2c) < 0)
635 case SENSOR_OV7630_3: {
636 __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
638 i2c[1] = sd->sensor_addr;
640 if (i2c_w(gspca_dev, i2c) < 0)
647 PDEBUG(D_ERR, "i2c error gain");
650 static void setgain(struct gspca_dev *gspca_dev)
652 struct sd *sd = (struct sd *) gspca_dev;
656 gain = sd->gain >> 4;
658 /* red and blue gain */
659 rgb_value = gain << 4 | gain;
660 reg_w(gspca_dev, 0x10, &rgb_value, 1);
663 reg_w(gspca_dev, 0x11, &rgb_value, 1);
665 if (sd->sensor_has_gain)
666 setsensorgain(gspca_dev);
669 static void setexposure(struct gspca_dev *gspca_dev)
671 struct sd *sd = (struct sd *) gspca_dev;
673 switch (sd->sensor) {
674 case SENSOR_TAS5110: {
677 /* register 19's high nibble contains the sn9c10x clock divider
678 The high nibble configures the no fps according to the
679 formula: 60 / high_nibble. With a maximum of 30 fps */
680 reg = 120 * sd->exposure / 1000;
685 reg = (reg << 4) | 0x0b;
686 reg_w(gspca_dev, 0x19, ®, 1);
690 case SENSOR_OV7630_3: {
691 /* The ov6650 / ov7630 have 2 registers which both influence
692 exposure, register 11, whose low nibble sets the nr off fps
693 according to: fps = 30 / (low_nibble + 1)
695 The fps configures the maximum exposure setting, but it is
696 possible to use less exposure then what the fps maximum
697 allows by setting register 10. register 10 configures the
698 actual exposure as quotient of the full exposure, with 0
699 being no exposure at all (not very usefull) and reg10_max
700 being max exposure possible at that framerate.
702 The code maps our 0 - 510 ms exposure ctrl to these 2
703 registers, trying to keep fps as high as possible.
705 __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
707 /* ov6645 datasheet says reg10_max is 9a, but that uses
708 tline * 2 * reg10 as formula for calculating texpo, the
709 ov6650 probably uses the same formula as the 7730 which uses
710 tline * 4 * reg10, which explains why the reg10max we've
711 found experimentally for the ov6650 is exactly half that of
712 the ov6645. The ov7630 datasheet says the max is 0x41. */
713 const int reg10_max = (sd->sensor == SENSOR_OV6650)
716 reg11 = (60 * sd->exposure + 999) / 1000;
722 /* frame exposure time in ms = 1000 * reg11 / 30 ->
723 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
724 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
726 /* Don't allow this to get below 10 when using autogain, the
727 steps become very large (relatively) when below 10 causing
728 the image to oscilate from much too dark, to much too bright
730 if (sd->autogain && reg10 < 10)
732 else if (reg10 > reg10_max)
735 /* Write reg 10 and reg11 low nibble */
736 i2c[1] = sd->sensor_addr;
739 if (sd->sensor == SENSOR_OV7630_3) {
740 __u8 reg76 = reg10 & 0x03;
741 __u8 i2c_reg76[] = {0xa0, 0x21, 0x76, 0x00,
742 0x00, 0x00, 0x00, 0x10};
744 i2c_reg76[3] = reg76;
745 if (i2c_w(gspca_dev, i2c_reg76) < 0)
746 PDEBUG(D_ERR, "i2c error exposure");
748 if (i2c_w(gspca_dev, i2c) < 0)
749 PDEBUG(D_ERR, "i2c error exposure");
755 static void setfreq(struct gspca_dev *gspca_dev)
757 struct sd *sd = (struct sd *) gspca_dev;
759 switch (sd->sensor) {
761 case SENSOR_OV7630_3: {
762 /* Framerate adjust register for artificial light 50 hz flicker
763 compensation, identical to ov6630 0x2b register, see ov6630
765 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
766 __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
769 /* case 0: * no filter*/
770 /* case 2: * 60 hz */
774 i2c[3] = (sd->sensor == SENSOR_OV6650)
778 i2c[1] = sd->sensor_addr;
779 if (i2c_w(gspca_dev, i2c) < 0)
780 PDEBUG(D_ERR, "i2c error setfreq");
786 static void setsaturation(struct gspca_dev *gspca_dev)
788 struct sd *sd = (struct sd *) gspca_dev;
790 switch (sd->sensor) {
791 /* case SENSOR_OV6650: */
792 case SENSOR_OV7630_3:
793 case SENSOR_OV7630: {
794 __u8 i2c[] = {0xa0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10};
795 i2c[1] = sd->sensor_addr;
796 i2c[3] = sd->saturation & 0xf0;
797 if (i2c_w(gspca_dev, i2c) < 0)
798 PDEBUG(D_ERR, "i2c error setsaturation");
800 PDEBUG(D_CONF, "saturation set to: %d",
801 (int)sd->saturation);
807 static void sethue(struct gspca_dev *gspca_dev)
809 struct sd *sd = (struct sd *) gspca_dev;
811 switch (sd->sensor) {
812 /* case SENSOR_OV6650: */
813 case SENSOR_OV7630_3:
814 case SENSOR_OV7630: {
815 __u8 i2c[] = {0xa0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10};
816 i2c[1] = sd->sensor_addr;
817 i2c[3] = 0x20 | (sd->hue >> 3);
818 if (i2c_w(gspca_dev, i2c) < 0)
819 PDEBUG(D_ERR, "i2c error setsaturation");
821 PDEBUG(D_CONF, "hue set to: %d", (int)sd->hue);
827 static void setcontrast(struct gspca_dev *gspca_dev)
829 struct sd *sd = (struct sd *) gspca_dev;
831 switch (sd->sensor) {
832 /* case SENSOR_OV6650: */
833 case SENSOR_OV7630_3:
834 case SENSOR_OV7630: {
835 __u8 i2c[] = {0xa0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10};
836 i2c[1] = sd->sensor_addr;
837 i2c[3] = 0x20 | (sd->contrast >> 3);
838 if (i2c_w(gspca_dev, i2c) < 0)
839 PDEBUG(D_ERR, "i2c error setcontrast");
841 PDEBUG(D_CONF, "contrast set to: %d",
849 static void do_autogain(struct gspca_dev *gspca_dev)
851 struct sd *sd = (struct sd *) gspca_dev;
852 int avg_lum = atomic_read(&sd->avg_lum);
857 if (sd->autogain_ignore_frames > 0)
858 sd->autogain_ignore_frames--;
859 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
860 sd->brightness * DESIRED_AVG_LUM / 127,
861 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
862 PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
863 (int)sd->gain, (int)sd->exposure);
864 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
868 /* this function is called at probe time */
869 static int sd_config(struct gspca_dev *gspca_dev,
870 const struct usb_device_id *id)
872 struct sd *sd = (struct sd *) gspca_dev;
877 /* nctrls depends upon the sensor, so we use a per cam copy */
878 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
879 gspca_dev->sd_desc = &sd->sd_desc;
881 sd->fr_h_sz = 12; /* default size of the frame header */
882 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
883 sd->autogain = AUTOGAIN_DEF; /* default is autogain active */
885 product = id->idProduct;
886 /* switch (id->idVendor) { */
887 /* case 0x0c45: * Sonix */
889 case 0x6001: /* SN9C102 */
890 case 0x6005: /* SN9C101 */
891 case 0x6007: /* SN9C101 */
892 sd->sensor = SENSOR_TAS5110;
893 sd->sensor_has_gain = 1;
894 sd->sd_desc.nctrls = 4;
895 sd->sd_desc.dq_callback = do_autogain;
898 case 0x6009: /* SN9C101 */
899 case 0x600d: /* SN9C101 */
900 case 0x6029: /* SN9C101 */
901 sd->sensor = SENSOR_PAS106;
904 case 0x6011: /* SN9C101 - SN9C101G */
905 sd->sensor = SENSOR_OV6650;
906 sd->sensor_has_gain = 1;
907 sd->sensor_addr = 0x60;
908 sd->sd_desc.nctrls = 5;
909 sd->sd_desc.dq_callback = do_autogain;
912 case 0x6019: /* SN9C101 */
913 case 0x602c: /* SN9C102 */
914 case 0x602e: /* SN9C102 */
915 sd->sensor = SENSOR_OV7630;
916 sd->sensor_addr = 0x21;
918 case 0x60b0: /* SN9C103 */
919 sd->sensor = SENSOR_OV7630_3;
920 sd->sensor_addr = 0x21;
921 sd->fr_h_sz = 18; /* size of frame header */
922 sd->sensor_has_gain = 1;
923 sd->sd_desc.nctrls = 8;
924 sd->sd_desc.dq_callback = do_autogain;
927 case 0x6024: /* SN9C102 */
928 case 0x6025: /* SN9C102 */
929 sd->sensor = SENSOR_TAS5130CXX;
931 case 0x6028: /* SN9C102 */
932 sd->sensor = SENSOR_PAS202;
934 case 0x602d: /* SN9C102 */
935 sd->sensor = SENSOR_HV7131R;
937 case 0x60af: /* SN9C103 */
938 sd->sensor = SENSOR_PAS202;
939 sd->fr_h_sz = 18; /* size of frame header (?) */
945 cam = &gspca_dev->cam;
946 cam->dev_name = (char *) id->driver_info;
949 cam->cam_mode = vga_mode;
950 cam->nmodes = ARRAY_SIZE(vga_mode);
951 if (sd->sensor == SENSOR_OV7630_3) {
952 /* We only have 320x240 & 640x480 */
957 cam->cam_mode = sif_mode;
958 cam->nmodes = ARRAY_SIZE(sif_mode);
960 sd->brightness = BRIGHTNESS_DEF;
962 sd->exposure = EXPOSURE_DEF;
964 sd->contrast = CONTRAST_DEF;
965 sd->saturation = SATURATION_DEF;
967 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
968 reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
972 /* this function is called at open time */
973 static int sd_open(struct gspca_dev *gspca_dev)
975 reg_r(gspca_dev, 0x00);
976 if (gspca_dev->usb_buf[0] != 0x10)
981 static void pas106_i2cinit(struct gspca_dev *gspca_dev)
985 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
987 i = ARRAY_SIZE(pas106_data);
988 data = pas106_data[0];
990 memcpy(&i2c1[2], data, 2);
991 /* copy 2 bytes from the template */
992 if (i2c_w(gspca_dev, i2c1) < 0)
993 PDEBUG(D_ERR, "i2c error pas106");
998 /* -- start the camera -- */
999 static void sd_start(struct gspca_dev *gspca_dev)
1001 struct sd *sd = (struct sd *) gspca_dev;
1003 const __u8 *sn9c10x;
1007 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
1008 switch (sd->sensor) {
1009 case SENSOR_HV7131R:
1010 sn9c10x = initHv7131;
1012 reg17_19[1] = (mode << 4) | 0x8a;
1016 sn9c10x = initOv6650;
1018 reg17_19[1] = (mode << 4) | 0x8b;
1022 sn9c10x = initOv7630;
1024 reg17_19[1] = (mode << 4) | COMP2;
1025 reg17_19[2] = MCK_INIT1;
1027 case SENSOR_OV7630_3:
1028 sn9c10x = initOv7630_3;
1030 reg17_19[1] = (mode << 4) | COMP2;
1031 reg17_19[2] = MCK_INIT1;
1034 sn9c10x = initPas106;
1035 reg17_19[0] = 0x24; /* 0x28 */
1036 reg17_19[1] = (mode << 4) | COMP1;
1037 reg17_19[2] = MCK_INIT1;
1040 sn9c10x = initPas202;
1041 reg17_19[0] = mode ? 0x24 : 0x20;
1042 reg17_19[1] = (mode << 4) | 0x89;
1045 case SENSOR_TAS5110:
1046 sn9c10x = initTas5110;
1048 reg17_19[1] = (mode << 4) | 0x86;
1049 reg17_19[2] = 0x2b; /* 0xf3; */
1052 /* case SENSOR_TAS5130CXX: */
1053 sn9c10x = initTas5130;
1055 reg17_19[1] = (mode << 4) | COMP;
1056 reg17_19[2] = mode ? 0x23 : 0x43;
1059 switch (sd->sensor) {
1063 l = sizeof initOv7630;
1065 case SENSOR_OV7630_3:
1068 l = sizeof initOv7630_3;
1072 reg17 = sn9c10x[0x17 - 1];
1077 /* reg 0x01 bit 2 video transfert on */
1078 reg_w(gspca_dev, 0x01, ®01, 1);
1079 /* reg 0x17 SensorClk enable inv Clk 0x60 */
1080 reg_w(gspca_dev, 0x17, ®17, 1);
1081 /*fixme: for ov7630 102
1082 reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
1083 /* Set the registers from the template */
1084 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
1085 switch (sd->sensor) {
1086 case SENSOR_HV7131R:
1087 i2c_w_vector(gspca_dev, hv7131_sensor_init,
1088 sizeof hv7131_sensor_init);
1091 i2c_w_vector(gspca_dev, ov6650_sensor_init,
1092 sizeof ov6650_sensor_init);
1095 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
1096 sizeof ov7630_sensor_init_com);
1098 i2c_w_vector(gspca_dev, ov7630_sensor_init,
1099 sizeof ov7630_sensor_init);
1101 case SENSOR_OV7630_3:
1102 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
1103 sizeof ov7630_sensor_init_com);
1105 i2c_w(gspca_dev, ov7630_sensor_init_3[mode]);
1108 pas106_i2cinit(gspca_dev);
1111 i2c_w_vector(gspca_dev, pas202_sensor_init,
1112 sizeof pas202_sensor_init);
1114 case SENSOR_TAS5110:
1115 i2c_w_vector(gspca_dev, tas5110_sensor_init,
1116 sizeof tas5110_sensor_init);
1119 /* case SENSOR_TAS5130CXX: */
1120 i2c_w_vector(gspca_dev, tas5130_sensor_init,
1121 sizeof tas5130_sensor_init);
1124 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
1125 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
1126 /* compression register */
1127 reg_w(gspca_dev, 0x18, ®17_19[1], 1);
1129 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
1131 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
1132 /* reset 0x17 SensorClk enable inv Clk 0x60 */
1133 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
1134 reg_w(gspca_dev, 0x17, ®17_19[0], 1);
1135 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
1136 reg_w(gspca_dev, 0x19, ®17_19[2], 1);
1137 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
1138 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
1139 /* Enable video transfert */
1140 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
1142 reg_w(gspca_dev, 0x18, ®17_19[1], 2);
1146 setbrightness(gspca_dev);
1147 setexposure(gspca_dev);
1149 setsaturation(gspca_dev);
1151 setcontrast(gspca_dev);
1153 sd->autogain_ignore_frames = 0;
1154 atomic_set(&sd->avg_lum, -1);
1157 static void sd_stopN(struct gspca_dev *gspca_dev)
1161 ByteSend = 0x09; /* 0X00 */
1162 reg_w(gspca_dev, 0x01, &ByteSend, 1);
1165 static void sd_stop0(struct gspca_dev *gspca_dev)
1169 static void sd_close(struct gspca_dev *gspca_dev)
1173 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1174 struct gspca_frame *frame, /* target */
1175 unsigned char *data, /* isoc packet */
1176 int len) /* iso packet length */
1179 struct sd *sd = (struct sd *) gspca_dev;
1181 /* frames start with:
1182 * ff ff 00 c4 c4 96 synchro
1184 * xx (frame sequence / size / compression)
1185 * (xx) (idem - extra byte for sn9c103)
1186 * ll mm brightness sum inside auto exposure
1187 * ll mm brightness sum outside auto exposure
1188 * (xx xx xx xx xx) audio values for snc103
1190 if (len > 6 && len < 24) {
1191 for (i = 0; i < len - 6; i++) {
1192 if (data[0 + i] == 0xff
1193 && data[1 + i] == 0xff
1194 && data[2 + i] == 0x00
1195 && data[3 + i] == 0xc4
1196 && data[4 + i] == 0xc4
1197 && data[5 + i] == 0x96) { /* start of frame */
1198 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
1200 if (len - i < sd->fr_h_sz) {
1201 atomic_set(&sd->avg_lum, -1);
1202 PDEBUG(D_STREAM, "packet too short to"
1203 " get avg brightness");
1204 } else if (sd->fr_h_sz == 12) {
1205 atomic_set(&sd->avg_lum,
1207 (data[i + 9] << 8));
1209 atomic_set(&sd->avg_lum,
1211 (data[i + 10] << 8));
1213 data += i + sd->fr_h_sz;
1214 len -= i + sd->fr_h_sz;
1215 gspca_frame_add(gspca_dev, FIRST_PACKET,
1221 gspca_frame_add(gspca_dev, INTER_PACKET,
1225 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1227 struct sd *sd = (struct sd *) gspca_dev;
1229 sd->brightness = val;
1230 if (gspca_dev->streaming)
1231 setbrightness(gspca_dev);
1235 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1237 struct sd *sd = (struct sd *) gspca_dev;
1239 *val = sd->brightness;
1243 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
1245 struct sd *sd = (struct sd *) gspca_dev;
1248 if (gspca_dev->streaming)
1253 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
1255 struct sd *sd = (struct sd *) gspca_dev;
1261 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1263 struct sd *sd = (struct sd *) gspca_dev;
1266 if (gspca_dev->streaming)
1267 setexposure(gspca_dev);
1271 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1273 struct sd *sd = (struct sd *) gspca_dev;
1275 *val = sd->exposure;
1279 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1281 struct sd *sd = (struct sd *) gspca_dev;
1284 /* when switching to autogain set defaults to make sure
1285 we are on a valid point of the autogain gain /
1286 exposure knee graph, and give this change time to
1287 take effect before doing autogain. */
1289 sd->exposure = EXPOSURE_DEF;
1290 sd->gain = GAIN_DEF;
1291 if (gspca_dev->streaming) {
1292 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1293 setexposure(gspca_dev);
1301 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1303 struct sd *sd = (struct sd *) gspca_dev;
1305 *val = sd->autogain;
1309 static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1311 struct sd *sd = (struct sd *) gspca_dev;
1314 if (gspca_dev->streaming)
1319 static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1321 struct sd *sd = (struct sd *) gspca_dev;
1327 static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)
1329 struct sd *sd = (struct sd *) gspca_dev;
1331 sd->saturation = val;
1332 if (gspca_dev->streaming)
1333 setsaturation(gspca_dev);
1337 static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)
1339 struct sd *sd = (struct sd *) gspca_dev;
1341 *val = sd->saturation;
1345 static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
1347 struct sd *sd = (struct sd *) gspca_dev;
1350 if (gspca_dev->streaming)
1355 static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
1357 struct sd *sd = (struct sd *) gspca_dev;
1363 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1365 struct sd *sd = (struct sd *) gspca_dev;
1368 if (gspca_dev->streaming)
1369 setcontrast(gspca_dev);
1373 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1375 struct sd *sd = (struct sd *) gspca_dev;
1377 *val = sd->contrast;
1381 static int sd_querymenu(struct gspca_dev *gspca_dev,
1382 struct v4l2_querymenu *menu)
1385 case V4L2_CID_POWER_LINE_FREQUENCY:
1386 switch (menu->index) {
1387 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1388 strcpy((char *) menu->name, "NoFliker");
1390 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1391 strcpy((char *) menu->name, "50 Hz");
1393 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1394 strcpy((char *) menu->name, "60 Hz");
1402 /* sub-driver description */
1403 static const struct sd_desc sd_desc = {
1404 .name = MODULE_NAME,
1406 .nctrls = ARRAY_SIZE(sd_ctrls),
1407 .config = sd_config,
1413 .pkt_scan = sd_pkt_scan,
1414 .querymenu = sd_querymenu,
1417 /* -- module initialisation -- */
1418 #define DVNM(name) .driver_info = (kernel_ulong_t) name
1419 static __devinitdata struct usb_device_id device_table[] = {
1420 #ifndef CONFIG_USB_SN9C102
1421 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1422 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1423 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1424 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1425 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
1427 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
1428 #ifndef CONFIG_USB_SN9C102
1429 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1430 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1431 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1432 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1433 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1434 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1435 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1436 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1437 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1438 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
1442 MODULE_DEVICE_TABLE(usb, device_table);
1444 /* -- device connect -- */
1445 static int sd_probe(struct usb_interface *intf,
1446 const struct usb_device_id *id)
1448 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1452 static struct usb_driver sd_driver = {
1453 .name = MODULE_NAME,
1454 .id_table = device_table,
1456 .disconnect = gspca_disconnect,
1459 /* -- module insert / remove -- */
1460 static int __init sd_mod_init(void)
1462 if (usb_register(&sd_driver) < 0)
1464 PDEBUG(D_PROBE, "registered");
1467 static void __exit sd_mod_exit(void)
1469 usb_deregister(&sd_driver);
1470 PDEBUG(D_PROBE, "deregistered");
1473 module_init(sd_mod_init);
1474 module_exit(sd_mod_exit);