4 * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *Notes: * t613 + tas5130A
21 * * Focus to light do not balance well as in win.
22 * Quality in win is not good, but its kinda better.
23 * * Fix some "extraneous bytes", most of apps will show the image anyway
24 * * Gamma table, is there, but its really doing something?
25 * * 7~8 Fps, its ok, max on win its 10.
29 #define MODULE_NAME "t613"
31 #include <linux/slab.h>
34 #define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
36 MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
37 MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
38 MODULE_LICENSE("GPL");
41 struct gspca_dev gspca_dev
; /* !! must be the first item */
53 u8 awb
; /* set default r/g/b and activate */
63 SENSOR_LT168G
, /* must verify if this is the actual model */
66 /* V4L2 controls supported by the driver */
67 static int sd_setbrightness(struct gspca_dev
*gspca_dev
, __s32 val
);
68 static int sd_getbrightness(struct gspca_dev
*gspca_dev
, __s32
*val
);
69 static int sd_setcontrast(struct gspca_dev
*gspca_dev
, __s32 val
);
70 static int sd_getcontrast(struct gspca_dev
*gspca_dev
, __s32
*val
);
71 static int sd_setcolors(struct gspca_dev
*gspca_dev
, __s32 val
);
72 static int sd_getcolors(struct gspca_dev
*gspca_dev
, __s32
*val
);
73 static int sd_setlowlight(struct gspca_dev
*gspca_dev
, __s32 val
);
74 static int sd_getlowlight(struct gspca_dev
*gspca_dev
, __s32
*val
);
75 static int sd_setgamma(struct gspca_dev
*gspca_dev
, __s32 val
);
76 static int sd_getgamma(struct gspca_dev
*gspca_dev
, __s32
*val
);
77 static int sd_setsharpness(struct gspca_dev
*gspca_dev
, __s32 val
);
78 static int sd_getsharpness(struct gspca_dev
*gspca_dev
, __s32
*val
);
79 static int sd_setfreq(struct gspca_dev
*gspca_dev
, __s32 val
);
80 static int sd_getfreq(struct gspca_dev
*gspca_dev
, __s32
*val
);
82 static int sd_setawb(struct gspca_dev
*gspca_dev
, __s32 val
);
83 static int sd_getawb(struct gspca_dev
*gspca_dev
, __s32
*val
);
84 static int sd_setblue_gain(struct gspca_dev
*gspca_dev
, __s32 val
);
85 static int sd_getblue_gain(struct gspca_dev
*gspca_dev
, __s32
*val
);
86 static int sd_setred_gain(struct gspca_dev
*gspca_dev
, __s32 val
);
87 static int sd_getred_gain(struct gspca_dev
*gspca_dev
, __s32
*val
);
88 static int sd_setgain(struct gspca_dev
*gspca_dev
, __s32 val
);
89 static int sd_getgain(struct gspca_dev
*gspca_dev
, __s32
*val
);
91 static int sd_setmirror(struct gspca_dev
*gspca_dev
, __s32 val
);
92 static int sd_getmirror(struct gspca_dev
*gspca_dev
, __s32
*val
);
93 static int sd_seteffect(struct gspca_dev
*gspca_dev
, __s32 val
);
94 static int sd_geteffect(struct gspca_dev
*gspca_dev
, __s32
*val
);
95 static int sd_querymenu(struct gspca_dev
*gspca_dev
,
96 struct v4l2_querymenu
*menu
);
98 static const struct ctrl sd_ctrls
[] = {
101 .id
= V4L2_CID_BRIGHTNESS
,
102 .type
= V4L2_CTRL_TYPE_INTEGER
,
103 .name
= "Brightness",
107 #define BRIGHTNESS_DEF 8
108 .default_value
= BRIGHTNESS_DEF
,
110 .set
= sd_setbrightness
,
111 .get
= sd_getbrightness
,
115 .id
= V4L2_CID_CONTRAST
,
116 .type
= V4L2_CTRL_TYPE_INTEGER
,
121 #define CONTRAST_DEF 0x07
122 .default_value
= CONTRAST_DEF
,
124 .set
= sd_setcontrast
,
125 .get
= sd_getcontrast
,
129 .id
= V4L2_CID_SATURATION
,
130 .type
= V4L2_CTRL_TYPE_INTEGER
,
135 #define COLORS_DEF 0x05
136 .default_value
= COLORS_DEF
,
145 .id
= V4L2_CID_GAMMA
, /* (gamma on win) */
146 .type
= V4L2_CTRL_TYPE_INTEGER
,
149 .maximum
= GAMMA_MAX
- 1,
151 .default_value
= GAMMA_DEF
,
158 .id
= V4L2_CID_BACKLIGHT_COMPENSATION
, /* Activa lowlight,
159 * some apps dont bring up the
160 * backligth_compensation control) */
161 .type
= V4L2_CTRL_TYPE_INTEGER
,
166 #define AUTOGAIN_DEF 0x01
167 .default_value
= AUTOGAIN_DEF
,
169 .set
= sd_setlowlight
,
170 .get
= sd_getlowlight
,
174 .id
= V4L2_CID_HFLIP
,
175 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
176 .name
= "Mirror Image",
181 .default_value
= MIRROR_DEF
,
188 .id
= V4L2_CID_POWER_LINE_FREQUENCY
,
189 .type
= V4L2_CTRL_TYPE_MENU
,
190 .name
= "Light Frequency Filter",
191 .minimum
= 1, /* 1 -> 0x50, 2->0x60 */
195 .default_value
= FREQ_DEF
,
202 .id
= V4L2_CID_AUTO_WHITE_BALANCE
,
203 .type
= V4L2_CTRL_TYPE_INTEGER
,
204 .name
= "Auto White Balance",
209 .default_value
= AWB_DEF
,
216 .id
= V4L2_CID_SHARPNESS
,
217 .type
= V4L2_CTRL_TYPE_INTEGER
,
222 #define SHARPNESS_DEF 0x06
223 .default_value
= SHARPNESS_DEF
,
225 .set
= sd_setsharpness
,
226 .get
= sd_getsharpness
,
230 .id
= V4L2_CID_EFFECTS
,
231 .type
= V4L2_CTRL_TYPE_MENU
,
232 .name
= "Webcam Effects",
236 #define EFFECTS_DEF 0
237 .default_value
= EFFECTS_DEF
,
244 .id
= V4L2_CID_BLUE_BALANCE
,
245 .type
= V4L2_CTRL_TYPE_INTEGER
,
246 .name
= "Blue Balance",
250 #define BLUE_GAIN_DEF 0x20
251 .default_value
= BLUE_GAIN_DEF
,
253 .set
= sd_setblue_gain
,
254 .get
= sd_getblue_gain
,
258 .id
= V4L2_CID_RED_BALANCE
,
259 .type
= V4L2_CTRL_TYPE_INTEGER
,
260 .name
= "Red Balance",
264 #define RED_GAIN_DEF 0x20
265 .default_value
= RED_GAIN_DEF
,
267 .set
= sd_setred_gain
,
268 .get
= sd_getred_gain
,
273 .type
= V4L2_CTRL_TYPE_INTEGER
,
278 #define GAIN_DEF 0x20
279 .default_value
= GAIN_DEF
,
286 static const struct v4l2_pix_format vga_mode_t16
[] = {
287 {160, 120, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
289 .sizeimage
= 160 * 120 * 4 / 8 + 590,
290 .colorspace
= V4L2_COLORSPACE_JPEG
,
292 {176, 144, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
294 .sizeimage
= 176 * 144 * 3 / 8 + 590,
295 .colorspace
= V4L2_COLORSPACE_JPEG
,
297 {320, 240, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
299 .sizeimage
= 320 * 240 * 3 / 8 + 590,
300 .colorspace
= V4L2_COLORSPACE_JPEG
,
302 {352, 288, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
304 .sizeimage
= 352 * 288 * 3 / 8 + 590,
305 .colorspace
= V4L2_COLORSPACE_JPEG
,
307 {640, 480, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
309 .sizeimage
= 640 * 480 * 3 / 8 + 590,
310 .colorspace
= V4L2_COLORSPACE_JPEG
,
314 /* sensor specific data */
315 struct additional_sensor_data
{
318 const u8 reg80
, reg8e
;
327 static const u8 n4_om6802
[] = {
328 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
329 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
330 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
331 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
332 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
333 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
334 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
335 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
336 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
338 static const u8 n4_other
[] = {
339 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
340 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
341 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
342 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
343 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
344 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
345 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
346 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
348 static const u8 n4_tas5130a
[] = {
349 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
350 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
351 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
352 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
353 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
354 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
357 static const u8 n4_lt168g
[] = {
358 0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
359 0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
360 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
361 0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
362 0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
363 0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
364 0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
365 0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
366 0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
369 static const struct additional_sensor_data sensor_data
[] = {
372 {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
374 .n4sz
= sizeof n4_om6802
,
377 .nset8
= {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
379 {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
382 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
385 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
387 .data5
= /* this could be removed later */
388 {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
390 {0x0b, 0x04, 0x0a, 0x78},
394 {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
396 .n4sz
= sizeof n4_other
,
399 .nset8
= {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
401 {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
404 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
407 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
410 {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
412 {0x0b, 0x04, 0x0a, 0x00},
414 [SENSOR_TAS5130A
] = {
416 {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
418 .n4sz
= sizeof n4_tas5130a
,
421 .nset8
= {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
423 {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
426 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
429 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
432 {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
434 {0x0b, 0x04, 0x0a, 0x40},
437 .n3
= {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
439 .n4sz
= sizeof n4_lt168g
,
442 .nset8
= {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
443 .data1
= {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
445 .data2
= {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
447 .data3
= {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
449 .data5
= {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
450 .stream
= {0x0b, 0x04, 0x0a, 0x28},
454 #define MAX_EFFECTS 7
455 /* easily done by soft, this table could be removed,
456 * i keep it here just in case */
457 static char *effects_control
[MAX_EFFECTS
] = {
459 "Emboss", /* disabled */
463 "Sun Effect", /* disabled */
466 static const u8 effects_table
[MAX_EFFECTS
][6] = {
467 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
468 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
469 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
470 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */
471 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */
472 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */
473 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
476 static const u8 gamma_table
[GAMMA_MAX
][17] = {
477 /* gamma table from cam1690.ini */
478 {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */
479 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
481 {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */
482 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
484 {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */
485 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
487 {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */
488 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
490 {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */
491 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
493 {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */
494 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
496 {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */
497 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
499 {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */
500 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
502 {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */
503 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
505 {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */
506 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
508 {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */
509 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
511 {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */
512 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
514 {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
515 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
517 {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */
518 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
520 {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */
521 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
523 {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */
524 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
528 static const u8 tas5130a_sensor_init
[][8] = {
529 {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
530 {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
531 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
534 static u8 sensor_reset
[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
537 static u8
reg_r(struct gspca_dev
*gspca_dev
,
540 usb_control_msg(gspca_dev
->dev
,
541 usb_rcvctrlpipe(gspca_dev
->dev
, 0),
543 USB_DIR_IN
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
546 gspca_dev
->usb_buf
, 1, 500);
547 return gspca_dev
->usb_buf
[0];
550 static void reg_w(struct gspca_dev
*gspca_dev
,
553 usb_control_msg(gspca_dev
->dev
,
554 usb_sndctrlpipe(gspca_dev
->dev
, 0),
556 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
561 static void reg_w_buf(struct gspca_dev
*gspca_dev
,
562 const u8
*buffer
, u16 len
)
564 if (len
<= USB_BUF_SZ
) {
565 memcpy(gspca_dev
->usb_buf
, buffer
, len
);
566 usb_control_msg(gspca_dev
->dev
,
567 usb_sndctrlpipe(gspca_dev
->dev
, 0),
569 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
571 gspca_dev
->usb_buf
, len
, 500);
575 tmpbuf
= kmemdup(buffer
, len
, GFP_KERNEL
);
577 err("Out of memory");
580 usb_control_msg(gspca_dev
->dev
,
581 usb_sndctrlpipe(gspca_dev
->dev
, 0),
583 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
590 /* write values to consecutive registers */
591 static void reg_w_ixbuf(struct gspca_dev
*gspca_dev
,
593 const u8
*buffer
, u16 len
)
598 if (len
* 2 <= USB_BUF_SZ
) {
599 p
= tmpbuf
= gspca_dev
->usb_buf
;
601 p
= tmpbuf
= kmalloc(len
* 2, GFP_KERNEL
);
603 err("Out of memory");
612 usb_control_msg(gspca_dev
->dev
,
613 usb_sndctrlpipe(gspca_dev
->dev
, 0),
615 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
617 tmpbuf
, len
* 2, 500);
618 if (len
* 2 > USB_BUF_SZ
)
622 static void om6802_sensor_init(struct gspca_dev
*gspca_dev
)
627 u8 val
[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
628 static const u8 sensor_init
[] = {
646 reg_w_buf(gspca_dev
, sensor_reset
, sizeof sensor_reset
);
650 byte
= reg_r(gspca_dev
, 0x0060);
655 byte
= reg_r(gspca_dev
, 0x0063);
657 err("Bad sensor reset %02x", byte
);
666 reg_w(gspca_dev
, 0x3c80);
667 reg_w_buf(gspca_dev
, val
, sizeof val
);
671 byte
= reg_r(gspca_dev
, 0x60);
677 reg_w(gspca_dev
, 0x3c80);
680 /* this function is called at probe time */
681 static int sd_config(struct gspca_dev
*gspca_dev
,
682 const struct usb_device_id
*id
)
684 struct sd
*sd
= (struct sd
*) gspca_dev
;
687 cam
= &gspca_dev
->cam
;
689 cam
->cam_mode
= vga_mode_t16
;
690 cam
->nmodes
= ARRAY_SIZE(vga_mode_t16
);
692 sd
->brightness
= BRIGHTNESS_DEF
;
693 sd
->contrast
= CONTRAST_DEF
;
694 sd
->colors
= COLORS_DEF
;
695 sd
->gamma
= GAMMA_DEF
;
696 sd
->autogain
= AUTOGAIN_DEF
;
697 sd
->mirror
= MIRROR_DEF
;
700 sd
->sharpness
= SHARPNESS_DEF
;
701 sd
->effect
= EFFECTS_DEF
;
702 sd
->red_gain
= RED_GAIN_DEF
;
703 sd
->blue_gain
= BLUE_GAIN_DEF
;
704 sd
->green_gain
= GAIN_DEF
* 3 - RED_GAIN_DEF
- BLUE_GAIN_DEF
;
709 static void setbrightness(struct gspca_dev
*gspca_dev
)
711 struct sd
*sd
= (struct sd
*) gspca_dev
;
712 unsigned int brightness
;
713 u8 set6
[4] = { 0x8f, 0x24, 0xc3, 0x00 };
715 brightness
= sd
->brightness
;
716 if (brightness
< 7) {
718 set6
[3] = 0x70 - brightness
* 0x10;
720 set6
[3] = 0x00 + ((brightness
- 7) * 0x10);
723 reg_w_buf(gspca_dev
, set6
, sizeof set6
);
726 static void setcontrast(struct gspca_dev
*gspca_dev
)
728 struct sd
*sd
= (struct sd
*) gspca_dev
;
729 unsigned int contrast
= sd
->contrast
;
733 reg_to_write
= 0x8ea9 - contrast
* 0x200;
735 reg_to_write
= 0x00a9 + (contrast
- 7) * 0x200;
737 reg_w(gspca_dev
, reg_to_write
);
740 static void setcolors(struct gspca_dev
*gspca_dev
)
742 struct sd
*sd
= (struct sd
*) gspca_dev
;
745 reg_to_write
= 0x80bb + sd
->colors
* 0x100; /* was 0xc0 */
746 reg_w(gspca_dev
, reg_to_write
);
749 static void setgamma(struct gspca_dev
*gspca_dev
)
751 struct sd
*sd
= (struct sd
*) gspca_dev
;
753 PDEBUG(D_CONF
, "Gamma: %d", sd
->gamma
);
754 reg_w_ixbuf(gspca_dev
, 0x90,
755 gamma_table
[sd
->gamma
], sizeof gamma_table
[0]);
758 static void setRGB(struct gspca_dev
*gspca_dev
)
760 struct sd
*sd
= (struct sd
*) gspca_dev
;
762 {0x87, 0x00, 0x88, 0x00, 0x89, 0x00};
764 all_gain_reg
[1] = sd
->red_gain
;
765 all_gain_reg
[3] = sd
->blue_gain
;
766 all_gain_reg
[5] = sd
->green_gain
;
767 reg_w_buf(gspca_dev
, all_gain_reg
, sizeof all_gain_reg
);
770 /* Generic fnc for r/b balance, exposure and awb */
771 static void setawb(struct gspca_dev
*gspca_dev
)
773 struct sd
*sd
= (struct sd
*) gspca_dev
;
776 reg80
= (sensor_data
[sd
->sensor
].reg80
<< 8) | 0x80;
778 /* on awb leave defaults values */
780 /* shoud we wait here.. */
781 /* update and reset RGB gains with webcam values */
782 sd
->red_gain
= reg_r(gspca_dev
, 0x0087);
783 sd
->blue_gain
= reg_r(gspca_dev
, 0x0088);
784 sd
->green_gain
= reg_r(gspca_dev
, 0x0089);
785 reg80
&= ~0x0400; /* AWB off */
787 reg_w(gspca_dev
, reg80
);
788 reg_w(gspca_dev
, reg80
);
791 static void init_gains(struct gspca_dev
*gspca_dev
)
793 struct sd
*sd
= (struct sd
*) gspca_dev
;
796 {0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00};
798 all_gain_reg
[1] = sd
->red_gain
;
799 all_gain_reg
[3] = sd
->blue_gain
;
800 all_gain_reg
[5] = sd
->green_gain
;
801 reg80
= sensor_data
[sd
->sensor
].reg80
;
804 all_gain_reg
[7] = reg80
;
805 reg_w_buf(gspca_dev
, all_gain_reg
, sizeof all_gain_reg
);
807 reg_w(gspca_dev
, (sd
->red_gain
<< 8) + 0x87);
808 reg_w(gspca_dev
, (sd
->blue_gain
<< 8) + 0x88);
809 reg_w(gspca_dev
, (sd
->green_gain
<< 8) + 0x89);
812 static void setsharpness(struct gspca_dev
*gspca_dev
)
814 struct sd
*sd
= (struct sd
*) gspca_dev
;
817 reg_to_write
= 0x0aa6 + 0x1000 * sd
->sharpness
;
819 reg_w(gspca_dev
, reg_to_write
);
822 static void setfreq(struct gspca_dev
*gspca_dev
)
824 struct sd
*sd
= (struct sd
*) gspca_dev
;
826 u8 freq
[4] = { 0x66, 0x00, 0xa8, 0xe8 };
828 switch (sd
->sensor
) {
842 case 0: /* no flicker */
851 reg_w_buf(gspca_dev
, freq
, sizeof freq
);
854 /* this function is called at probe and resume time */
855 static int sd_init(struct gspca_dev
*gspca_dev
)
857 /* some of this registers are not really neded, because
858 * they are overriden by setbrigthness, setcontrast, etc,
859 * but wont hurt anyway, and can help someone with similar webcam
860 * to see the initial parameters.*/
861 struct sd
*sd
= (struct sd
*) gspca_dev
;
862 const struct additional_sensor_data
*sensor
;
867 static const u8 read_indexs
[] =
868 { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
869 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
870 static const u8 n1
[] =
871 {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
872 static const u8 n2
[] =
875 sensor_id
= (reg_r(gspca_dev
, 0x06) << 8)
876 | reg_r(gspca_dev
, 0x07);
877 switch (sensor_id
& 0xff0f) {
879 PDEBUG(D_PROBE
, "sensor tas5130a");
880 sd
->sensor
= SENSOR_TAS5130A
;
883 PDEBUG(D_PROBE
, "sensor lt168g");
884 sd
->sensor
= SENSOR_LT168G
;
887 PDEBUG(D_PROBE
, "sensor 'other'");
888 sd
->sensor
= SENSOR_OTHER
;
891 PDEBUG(D_PROBE
, "sensor om6802");
892 sd
->sensor
= SENSOR_OM6802
;
895 err("unknown sensor %04x", sensor_id
);
899 if (sd
->sensor
== SENSOR_OM6802
) {
900 reg_w_buf(gspca_dev
, n1
, sizeof n1
);
903 reg_w_buf(gspca_dev
, sensor_reset
, sizeof sensor_reset
);
904 test_byte
= reg_r(gspca_dev
, 0x0063);
906 if (test_byte
== 0x17)
910 err("Bad sensor reset %02x", test_byte
);
913 reg_w_buf(gspca_dev
, n2
, sizeof n2
);
917 while (read_indexs
[i
] != 0x00) {
918 test_byte
= reg_r(gspca_dev
, read_indexs
[i
]);
919 PDEBUG(D_STREAM
, "Reg 0x%02x = 0x%02x", read_indexs
[i
],
924 sensor
= &sensor_data
[sd
->sensor
];
925 reg_w_buf(gspca_dev
, sensor
->n3
, sizeof sensor
->n3
);
926 reg_w_buf(gspca_dev
, sensor
->n4
, sensor
->n4sz
);
928 if (sd
->sensor
== SENSOR_LT168G
) {
929 test_byte
= reg_r(gspca_dev
, 0x80);
930 PDEBUG(D_STREAM
, "Reg 0x%02x = 0x%02x", 0x80,
932 reg_w(gspca_dev
, 0x6c80);
935 reg_w_ixbuf(gspca_dev
, 0xd0, sensor
->data1
, sizeof sensor
->data1
);
936 reg_w_ixbuf(gspca_dev
, 0xc7, sensor
->data2
, sizeof sensor
->data2
);
937 reg_w_ixbuf(gspca_dev
, 0xe0, sensor
->data3
, sizeof sensor
->data3
);
939 reg_w(gspca_dev
, (sensor
->reg80
<< 8) + 0x80);
940 reg_w(gspca_dev
, (sensor
->reg80
<< 8) + 0x80);
941 reg_w(gspca_dev
, (sensor
->reg8e
<< 8) + 0x8e);
943 setbrightness(gspca_dev
);
944 setcontrast(gspca_dev
);
946 setcolors(gspca_dev
);
947 setsharpness(gspca_dev
);
948 init_gains(gspca_dev
);
951 reg_w_buf(gspca_dev
, sensor
->data5
, sizeof sensor
->data5
);
952 reg_w_buf(gspca_dev
, sensor
->nset8
, sizeof sensor
->nset8
);
953 reg_w_buf(gspca_dev
, sensor
->stream
, sizeof sensor
->stream
);
955 if (sd
->sensor
== SENSOR_LT168G
) {
956 test_byte
= reg_r(gspca_dev
, 0x80);
957 PDEBUG(D_STREAM
, "Reg 0x%02x = 0x%02x", 0x80,
959 reg_w(gspca_dev
, 0x6c80);
962 reg_w_ixbuf(gspca_dev
, 0xd0, sensor
->data1
, sizeof sensor
->data1
);
963 reg_w_ixbuf(gspca_dev
, 0xc7, sensor
->data2
, sizeof sensor
->data2
);
964 reg_w_ixbuf(gspca_dev
, 0xe0, sensor
->data3
, sizeof sensor
->data3
);
969 static void setmirror(struct gspca_dev
*gspca_dev
)
971 struct sd
*sd
= (struct sd
*) gspca_dev
;
973 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
978 reg_w_buf(gspca_dev
, hflipcmd
, sizeof hflipcmd
);
981 static void seteffect(struct gspca_dev
*gspca_dev
)
983 struct sd
*sd
= (struct sd
*) gspca_dev
;
985 reg_w_buf(gspca_dev
, effects_table
[sd
->effect
],
986 sizeof effects_table
[0]);
987 if (sd
->effect
== 1 || sd
->effect
== 5) {
989 "This effect have been disabled for webcam \"safety\"");
993 if (sd
->effect
== 1 || sd
->effect
== 4)
994 reg_w(gspca_dev
, 0x4aa6);
996 reg_w(gspca_dev
, 0xfaa6);
999 /* Is this really needed?
1000 * i added some module parameters for test with some users */
1001 static void poll_sensor(struct gspca_dev
*gspca_dev
)
1003 static const u8 poll1
[] =
1004 {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
1005 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
1006 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
1008 static const u8 poll2
[] =
1009 {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
1010 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
1011 static const u8 noise03
[] = /* (some differences / ms-drv) */
1012 {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
1013 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
1014 0xc2, 0x80, 0xc3, 0x10};
1016 PDEBUG(D_STREAM
, "[Sensor requires polling]");
1017 reg_w_buf(gspca_dev
, poll1
, sizeof poll1
);
1018 reg_w_buf(gspca_dev
, poll2
, sizeof poll2
);
1019 reg_w_buf(gspca_dev
, noise03
, sizeof noise03
);
1022 static int sd_start(struct gspca_dev
*gspca_dev
)
1024 struct sd
*sd
= (struct sd
*) gspca_dev
;
1025 const struct additional_sensor_data
*sensor
;
1027 u8 t2
[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
1028 static const u8 t3
[] =
1029 { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
1031 mode
= gspca_dev
->cam
.cam_mode
[gspca_dev
->curr_mode
].priv
;
1033 case 0: /* 640x480 (0x00) */
1035 case 1: /* 352x288 */
1038 case 2: /* 320x240 */
1041 case 3: /* 176x144 */
1045 /* case 4: * 160x120 */
1050 switch (sd
->sensor
) {
1052 om6802_sensor_init(gspca_dev
);
1054 case SENSOR_TAS5130A
:
1057 reg_w_buf(gspca_dev
, tas5130a_sensor_init
[i
],
1058 sizeof tas5130a_sensor_init
[0]);
1059 if (i
>= ARRAY_SIZE(tas5130a_sensor_init
) - 1)
1063 reg_w(gspca_dev
, 0x3c80);
1064 /* just in case and to keep sync with logs (for mine) */
1065 reg_w_buf(gspca_dev
, tas5130a_sensor_init
[i
],
1066 sizeof tas5130a_sensor_init
[0]);
1067 reg_w(gspca_dev
, 0x3c80);
1070 sensor
= &sensor_data
[sd
->sensor
];
1072 reg_r(gspca_dev
, 0x0012);
1073 reg_w_buf(gspca_dev
, t2
, sizeof t2
);
1074 reg_w_ixbuf(gspca_dev
, 0xb3, t3
, sizeof t3
);
1075 reg_w(gspca_dev
, 0x0013);
1077 reg_w_buf(gspca_dev
, sensor
->stream
, sizeof sensor
->stream
);
1078 reg_w_buf(gspca_dev
, sensor
->stream
, sizeof sensor
->stream
);
1080 if (sd
->sensor
== SENSOR_OM6802
)
1081 poll_sensor(gspca_dev
);
1086 static void sd_stopN(struct gspca_dev
*gspca_dev
)
1088 struct sd
*sd
= (struct sd
*) gspca_dev
;
1090 reg_w_buf(gspca_dev
, sensor_data
[sd
->sensor
].stream
,
1091 sizeof sensor_data
[sd
->sensor
].stream
);
1092 reg_w_buf(gspca_dev
, sensor_data
[sd
->sensor
].stream
,
1093 sizeof sensor_data
[sd
->sensor
].stream
);
1094 if (sd
->sensor
== SENSOR_OM6802
) {
1096 reg_w(gspca_dev
, 0x0309);
1100 static void sd_pkt_scan(struct gspca_dev
*gspca_dev
,
1101 u8
*data
, /* isoc packet */
1102 int len
) /* iso packet length */
1106 if (data
[0] == 0x5a) {
1107 /* Control Packet, after this came the header again,
1108 * but extra bytes came in the packet before this,
1109 * sometimes an EOF arrives, sometimes not... */
1114 if (data
[0] == 0xff && data
[1] == 0xd8)
1115 pkt_type
= FIRST_PACKET
;
1116 else if (data
[len
- 2] == 0xff && data
[len
- 1] == 0xd9)
1117 pkt_type
= LAST_PACKET
;
1119 pkt_type
= INTER_PACKET
;
1120 gspca_frame_add(gspca_dev
, pkt_type
, data
, len
);
1123 static int sd_setblue_gain(struct gspca_dev
*gspca_dev
, __s32 val
)
1125 struct sd
*sd
= (struct sd
*) gspca_dev
;
1127 sd
->blue_gain
= val
;
1128 if (gspca_dev
->streaming
)
1129 reg_w(gspca_dev
, (val
<< 8) + 0x88);
1133 static int sd_getblue_gain(struct gspca_dev
*gspca_dev
, __s32
*val
)
1135 struct sd
*sd
= (struct sd
*) gspca_dev
;
1137 *val
= sd
->blue_gain
;
1141 static int sd_setred_gain(struct gspca_dev
*gspca_dev
, __s32 val
)
1143 struct sd
*sd
= (struct sd
*) gspca_dev
;
1146 if (gspca_dev
->streaming
)
1147 reg_w(gspca_dev
, (val
<< 8) + 0x87);
1152 static int sd_getred_gain(struct gspca_dev
*gspca_dev
, __s32
*val
)
1154 struct sd
*sd
= (struct sd
*) gspca_dev
;
1156 *val
= sd
->red_gain
;
1160 static int sd_setgain(struct gspca_dev
*gspca_dev
, __s32 val
)
1162 struct sd
*sd
= (struct sd
*) gspca_dev
;
1165 psg
= sd
->red_gain
+ sd
->blue_gain
+ sd
->green_gain
;
1167 sd
->red_gain
= sd
->red_gain
* nsg
/ psg
;
1168 if (sd
->red_gain
> 0x40)
1169 sd
->red_gain
= 0x40;
1170 else if (sd
->red_gain
< 0x10)
1171 sd
->red_gain
= 0x10;
1172 sd
->blue_gain
= sd
->blue_gain
* nsg
/ psg
;
1173 if (sd
->blue_gain
> 0x40)
1174 sd
->blue_gain
= 0x40;
1175 else if (sd
->blue_gain
< 0x10)
1176 sd
->blue_gain
= 0x10;
1177 sd
->green_gain
= sd
->green_gain
* nsg
/ psg
;
1178 if (sd
->green_gain
> 0x40)
1179 sd
->green_gain
= 0x40;
1180 else if (sd
->green_gain
< 0x10)
1181 sd
->green_gain
= 0x10;
1183 if (gspca_dev
->streaming
)
1188 static int sd_getgain(struct gspca_dev
*gspca_dev
, __s32
*val
)
1190 struct sd
*sd
= (struct sd
*) gspca_dev
;
1192 *val
= (sd
->red_gain
+ sd
->blue_gain
+ sd
->green_gain
) / 3;
1196 static int sd_setbrightness(struct gspca_dev
*gspca_dev
, __s32 val
)
1198 struct sd
*sd
= (struct sd
*) gspca_dev
;
1200 sd
->brightness
= val
;
1201 if (gspca_dev
->streaming
)
1202 setbrightness(gspca_dev
);
1206 static int sd_getbrightness(struct gspca_dev
*gspca_dev
, __s32
*val
)
1208 struct sd
*sd
= (struct sd
*) gspca_dev
;
1210 *val
= sd
->brightness
;
1214 static int sd_setawb(struct gspca_dev
*gspca_dev
, __s32 val
)
1216 struct sd
*sd
= (struct sd
*) gspca_dev
;
1219 if (gspca_dev
->streaming
)
1224 static int sd_getawb(struct gspca_dev
*gspca_dev
, __s32
*val
)
1226 struct sd
*sd
= (struct sd
*) gspca_dev
;
1232 static int sd_setmirror(struct gspca_dev
*gspca_dev
, __s32 val
)
1234 struct sd
*sd
= (struct sd
*) gspca_dev
;
1237 if (gspca_dev
->streaming
)
1238 setmirror(gspca_dev
);
1242 static int sd_getmirror(struct gspca_dev
*gspca_dev
, __s32
*val
)
1244 struct sd
*sd
= (struct sd
*) gspca_dev
;
1250 static int sd_seteffect(struct gspca_dev
*gspca_dev
, __s32 val
)
1252 struct sd
*sd
= (struct sd
*) gspca_dev
;
1255 if (gspca_dev
->streaming
)
1256 seteffect(gspca_dev
);
1260 static int sd_geteffect(struct gspca_dev
*gspca_dev
, __s32
*val
)
1262 struct sd
*sd
= (struct sd
*) gspca_dev
;
1268 static int sd_setcontrast(struct gspca_dev
*gspca_dev
, __s32 val
)
1270 struct sd
*sd
= (struct sd
*) gspca_dev
;
1273 if (gspca_dev
->streaming
)
1274 setcontrast(gspca_dev
);
1278 static int sd_getcontrast(struct gspca_dev
*gspca_dev
, __s32
*val
)
1280 struct sd
*sd
= (struct sd
*) gspca_dev
;
1282 *val
= sd
->contrast
;
1286 static int sd_setcolors(struct gspca_dev
*gspca_dev
, __s32 val
)
1288 struct sd
*sd
= (struct sd
*) gspca_dev
;
1291 if (gspca_dev
->streaming
)
1292 setcolors(gspca_dev
);
1296 static int sd_getcolors(struct gspca_dev
*gspca_dev
, __s32
*val
)
1298 struct sd
*sd
= (struct sd
*) gspca_dev
;
1304 static int sd_setgamma(struct gspca_dev
*gspca_dev
, __s32 val
)
1306 struct sd
*sd
= (struct sd
*) gspca_dev
;
1309 if (gspca_dev
->streaming
)
1310 setgamma(gspca_dev
);
1314 static int sd_getgamma(struct gspca_dev
*gspca_dev
, __s32
*val
)
1316 struct sd
*sd
= (struct sd
*) gspca_dev
;
1322 static int sd_setfreq(struct gspca_dev
*gspca_dev
, __s32 val
)
1324 struct sd
*sd
= (struct sd
*) gspca_dev
;
1327 if (gspca_dev
->streaming
)
1332 static int sd_getfreq(struct gspca_dev
*gspca_dev
, __s32
*val
)
1334 struct sd
*sd
= (struct sd
*) gspca_dev
;
1340 static int sd_setsharpness(struct gspca_dev
*gspca_dev
, __s32 val
)
1342 struct sd
*sd
= (struct sd
*) gspca_dev
;
1344 sd
->sharpness
= val
;
1345 if (gspca_dev
->streaming
)
1346 setsharpness(gspca_dev
);
1350 static int sd_getsharpness(struct gspca_dev
*gspca_dev
, __s32
*val
)
1352 struct sd
*sd
= (struct sd
*) gspca_dev
;
1354 *val
= sd
->sharpness
;
1358 /* Low Light set here......*/
1359 static int sd_setlowlight(struct gspca_dev
*gspca_dev
, __s32 val
)
1361 struct sd
*sd
= (struct sd
*) gspca_dev
;
1365 reg_w(gspca_dev
, 0xf48e);
1367 reg_w(gspca_dev
, 0xb48e);
1371 static int sd_getlowlight(struct gspca_dev
*gspca_dev
, __s32
*val
)
1373 struct sd
*sd
= (struct sd
*) gspca_dev
;
1375 *val
= sd
->autogain
;
1379 static int sd_querymenu(struct gspca_dev
*gspca_dev
,
1380 struct v4l2_querymenu
*menu
)
1383 case V4L2_CID_POWER_LINE_FREQUENCY
:
1384 switch (menu
->index
) {
1385 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1386 strcpy((char *) menu
->name
, "50 Hz");
1388 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1389 strcpy((char *) menu
->name
, "60 Hz");
1393 case V4L2_CID_EFFECTS
:
1394 if ((unsigned) menu
->index
< ARRAY_SIZE(effects_control
)) {
1395 strncpy((char *) menu
->name
,
1396 effects_control
[menu
->index
],
1405 /* sub-driver description */
1406 static const struct sd_desc sd_desc
= {
1407 .name
= MODULE_NAME
,
1409 .nctrls
= ARRAY_SIZE(sd_ctrls
),
1410 .config
= sd_config
,
1414 .pkt_scan
= sd_pkt_scan
,
1415 .querymenu
= sd_querymenu
,
1418 /* -- module initialisation -- */
1419 static const struct usb_device_id device_table
[] = {
1420 {USB_DEVICE(0x17a1, 0x0128)},
1423 MODULE_DEVICE_TABLE(usb
, device_table
);
1425 /* -- device connect -- */
1426 static int sd_probe(struct usb_interface
*intf
,
1427 const struct usb_device_id
*id
)
1429 return gspca_dev_probe(intf
, id
, &sd_desc
, sizeof(struct sd
),
1433 static struct usb_driver sd_driver
= {
1434 .name
= MODULE_NAME
,
1435 .id_table
= device_table
,
1437 .disconnect
= gspca_disconnect
,
1439 .suspend
= gspca_suspend
,
1440 .resume
= gspca_resume
,
1444 /* -- module insert / remove -- */
1445 static int __init
sd_mod_init(void)
1447 return usb_register(&sd_driver
);
1449 static void __exit
sd_mod_exit(void)
1451 usb_deregister(&sd_driver
);
1454 module_init(sd_mod_init
);
1455 module_exit(sd_mod_exit
);