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
);
96 static const struct ctrl sd_ctrls
[] = {
99 .id
= V4L2_CID_BRIGHTNESS
,
100 .type
= V4L2_CTRL_TYPE_INTEGER
,
101 .name
= "Brightness",
105 #define BRIGHTNESS_DEF 8
106 .default_value
= BRIGHTNESS_DEF
,
108 .set
= sd_setbrightness
,
109 .get
= sd_getbrightness
,
113 .id
= V4L2_CID_CONTRAST
,
114 .type
= V4L2_CTRL_TYPE_INTEGER
,
119 #define CONTRAST_DEF 0x07
120 .default_value
= CONTRAST_DEF
,
122 .set
= sd_setcontrast
,
123 .get
= sd_getcontrast
,
127 .id
= V4L2_CID_SATURATION
,
128 .type
= V4L2_CTRL_TYPE_INTEGER
,
133 #define COLORS_DEF 0x05
134 .default_value
= COLORS_DEF
,
143 .id
= V4L2_CID_GAMMA
, /* (gamma on win) */
144 .type
= V4L2_CTRL_TYPE_INTEGER
,
147 .maximum
= GAMMA_MAX
- 1,
149 .default_value
= GAMMA_DEF
,
156 .id
= V4L2_CID_BACKLIGHT_COMPENSATION
, /* Activa lowlight,
157 * some apps dont bring up the
158 * backligth_compensation control) */
159 .type
= V4L2_CTRL_TYPE_INTEGER
,
164 #define AUTOGAIN_DEF 0x01
165 .default_value
= AUTOGAIN_DEF
,
167 .set
= sd_setlowlight
,
168 .get
= sd_getlowlight
,
172 .id
= V4L2_CID_HFLIP
,
173 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
174 .name
= "Mirror Image",
179 .default_value
= MIRROR_DEF
,
186 .id
= V4L2_CID_POWER_LINE_FREQUENCY
,
187 .type
= V4L2_CTRL_TYPE_MENU
,
188 .name
= "Light Frequency Filter",
189 .minimum
= 1, /* 1 -> 0x50, 2->0x60 */
193 .default_value
= FREQ_DEF
,
200 .id
= V4L2_CID_AUTO_WHITE_BALANCE
,
201 .type
= V4L2_CTRL_TYPE_INTEGER
,
202 .name
= "Auto White Balance",
207 .default_value
= AWB_DEF
,
214 .id
= V4L2_CID_SHARPNESS
,
215 .type
= V4L2_CTRL_TYPE_INTEGER
,
220 #define SHARPNESS_DEF 0x06
221 .default_value
= SHARPNESS_DEF
,
223 .set
= sd_setsharpness
,
224 .get
= sd_getsharpness
,
228 .id
= V4L2_CID_EFFECTS
,
229 .type
= V4L2_CTRL_TYPE_MENU
,
230 .name
= "Webcam Effects",
234 #define EFFECTS_DEF 0
235 .default_value
= EFFECTS_DEF
,
242 .id
= V4L2_CID_BLUE_BALANCE
,
243 .type
= V4L2_CTRL_TYPE_INTEGER
,
244 .name
= "Blue Balance",
248 #define BLUE_GAIN_DEF 0x20
249 .default_value
= BLUE_GAIN_DEF
,
251 .set
= sd_setblue_gain
,
252 .get
= sd_getblue_gain
,
256 .id
= V4L2_CID_RED_BALANCE
,
257 .type
= V4L2_CTRL_TYPE_INTEGER
,
258 .name
= "Red Balance",
262 #define RED_GAIN_DEF 0x20
263 .default_value
= RED_GAIN_DEF
,
265 .set
= sd_setred_gain
,
266 .get
= sd_getred_gain
,
271 .type
= V4L2_CTRL_TYPE_INTEGER
,
276 #define GAIN_DEF 0x20
277 .default_value
= GAIN_DEF
,
284 static const struct v4l2_pix_format vga_mode_t16
[] = {
285 {160, 120, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
287 .sizeimage
= 160 * 120 * 4 / 8 + 590,
288 .colorspace
= V4L2_COLORSPACE_JPEG
,
290 {176, 144, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
292 .sizeimage
= 176 * 144 * 3 / 8 + 590,
293 .colorspace
= V4L2_COLORSPACE_JPEG
,
295 {320, 240, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
297 .sizeimage
= 320 * 240 * 3 / 8 + 590,
298 .colorspace
= V4L2_COLORSPACE_JPEG
,
300 {352, 288, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
302 .sizeimage
= 352 * 288 * 3 / 8 + 590,
303 .colorspace
= V4L2_COLORSPACE_JPEG
,
305 {640, 480, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
307 .sizeimage
= 640 * 480 * 3 / 8 + 590,
308 .colorspace
= V4L2_COLORSPACE_JPEG
,
312 /* sensor specific data */
313 struct additional_sensor_data
{
316 const u8 reg80
, reg8e
;
325 static const u8 n4_om6802
[] = {
326 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
327 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
328 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
329 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
330 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
331 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
332 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
333 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
334 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
336 static const u8 n4_other
[] = {
337 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
338 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
339 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
340 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
341 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
342 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
343 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
344 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
346 static const u8 n4_tas5130a
[] = {
347 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
348 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
349 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
350 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
351 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
352 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
355 static const u8 n4_lt168g
[] = {
356 0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
357 0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
358 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
359 0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
360 0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
361 0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
362 0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
363 0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
364 0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
367 static const struct additional_sensor_data sensor_data
[] = {
370 {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
372 .n4sz
= sizeof n4_om6802
,
375 .nset8
= {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
377 {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
380 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
383 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
385 .data5
= /* this could be removed later */
386 {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
388 {0x0b, 0x04, 0x0a, 0x78},
392 {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
394 .n4sz
= sizeof n4_other
,
397 .nset8
= {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
399 {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
402 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
405 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
408 {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
410 {0x0b, 0x04, 0x0a, 0x00},
412 [SENSOR_TAS5130A
] = {
414 {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
416 .n4sz
= sizeof n4_tas5130a
,
419 .nset8
= {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
421 {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
424 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
427 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
430 {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
432 {0x0b, 0x04, 0x0a, 0x40},
435 .n3
= {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
437 .n4sz
= sizeof n4_lt168g
,
440 .nset8
= {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
441 .data1
= {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
443 .data2
= {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
445 .data3
= {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
447 .data5
= {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
448 .stream
= {0x0b, 0x04, 0x0a, 0x28},
452 #define MAX_EFFECTS 7
453 /* easily done by soft, this table could be removed,
454 * i keep it here just in case */
455 static char *effects_control
[MAX_EFFECTS
] = {
457 "Emboss", /* disabled */
461 "Sun Effect", /* disabled */
464 static const u8 effects_table
[MAX_EFFECTS
][6] = {
465 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
466 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
467 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
468 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */
469 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */
470 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */
471 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
474 static const u8 gamma_table
[GAMMA_MAX
][17] = {
475 /* gamma table from cam1690.ini */
476 {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */
477 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
479 {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */
480 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
482 {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */
483 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
485 {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */
486 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
488 {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */
489 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
491 {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */
492 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
494 {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */
495 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
497 {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */
498 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
500 {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */
501 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
503 {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */
504 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
506 {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */
507 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
509 {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */
510 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
512 {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
513 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
515 {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */
516 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
518 {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */
519 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
521 {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */
522 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
526 static const u8 tas5130a_sensor_init
[][8] = {
527 {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
528 {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
529 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
532 static u8 sensor_reset
[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
535 static u8
reg_r(struct gspca_dev
*gspca_dev
,
538 usb_control_msg(gspca_dev
->dev
,
539 usb_rcvctrlpipe(gspca_dev
->dev
, 0),
541 USB_DIR_IN
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
544 gspca_dev
->usb_buf
, 1, 500);
545 return gspca_dev
->usb_buf
[0];
548 static void reg_w(struct gspca_dev
*gspca_dev
,
551 usb_control_msg(gspca_dev
->dev
,
552 usb_sndctrlpipe(gspca_dev
->dev
, 0),
554 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
559 static void reg_w_buf(struct gspca_dev
*gspca_dev
,
560 const u8
*buffer
, u16 len
)
562 if (len
<= USB_BUF_SZ
) {
563 memcpy(gspca_dev
->usb_buf
, buffer
, len
);
564 usb_control_msg(gspca_dev
->dev
,
565 usb_sndctrlpipe(gspca_dev
->dev
, 0),
567 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
569 gspca_dev
->usb_buf
, len
, 500);
573 tmpbuf
= kmemdup(buffer
, len
, GFP_KERNEL
);
575 err("Out of memory");
578 usb_control_msg(gspca_dev
->dev
,
579 usb_sndctrlpipe(gspca_dev
->dev
, 0),
581 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
588 /* write values to consecutive registers */
589 static void reg_w_ixbuf(struct gspca_dev
*gspca_dev
,
591 const u8
*buffer
, u16 len
)
596 if (len
* 2 <= USB_BUF_SZ
) {
597 p
= tmpbuf
= gspca_dev
->usb_buf
;
599 p
= tmpbuf
= kmalloc(len
* 2, GFP_KERNEL
);
601 err("Out of memory");
610 usb_control_msg(gspca_dev
->dev
,
611 usb_sndctrlpipe(gspca_dev
->dev
, 0),
613 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
615 tmpbuf
, len
* 2, 500);
616 if (len
* 2 > USB_BUF_SZ
)
620 static void om6802_sensor_init(struct gspca_dev
*gspca_dev
)
625 u8 val
[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
626 static const u8 sensor_init
[] = {
644 reg_w_buf(gspca_dev
, sensor_reset
, sizeof sensor_reset
);
648 byte
= reg_r(gspca_dev
, 0x0060);
653 byte
= reg_r(gspca_dev
, 0x0063);
655 err("Bad sensor reset %02x", byte
);
664 reg_w(gspca_dev
, 0x3c80);
665 reg_w_buf(gspca_dev
, val
, sizeof val
);
669 byte
= reg_r(gspca_dev
, 0x60);
675 reg_w(gspca_dev
, 0x3c80);
678 /* this function is called at probe time */
679 static int sd_config(struct gspca_dev
*gspca_dev
,
680 const struct usb_device_id
*id
)
682 struct sd
*sd
= (struct sd
*) gspca_dev
;
685 cam
= &gspca_dev
->cam
;
687 cam
->cam_mode
= vga_mode_t16
;
688 cam
->nmodes
= ARRAY_SIZE(vga_mode_t16
);
690 sd
->brightness
= BRIGHTNESS_DEF
;
691 sd
->contrast
= CONTRAST_DEF
;
692 sd
->colors
= COLORS_DEF
;
693 sd
->gamma
= GAMMA_DEF
;
694 sd
->autogain
= AUTOGAIN_DEF
;
695 sd
->mirror
= MIRROR_DEF
;
698 sd
->sharpness
= SHARPNESS_DEF
;
699 sd
->effect
= EFFECTS_DEF
;
700 sd
->red_gain
= RED_GAIN_DEF
;
701 sd
->blue_gain
= BLUE_GAIN_DEF
;
702 sd
->green_gain
= GAIN_DEF
* 3 - RED_GAIN_DEF
- BLUE_GAIN_DEF
;
707 static void setbrightness(struct gspca_dev
*gspca_dev
)
709 struct sd
*sd
= (struct sd
*) gspca_dev
;
710 unsigned int brightness
;
711 u8 set6
[4] = { 0x8f, 0x24, 0xc3, 0x00 };
713 brightness
= sd
->brightness
;
714 if (brightness
< 7) {
716 set6
[3] = 0x70 - brightness
* 0x10;
718 set6
[3] = 0x00 + ((brightness
- 7) * 0x10);
721 reg_w_buf(gspca_dev
, set6
, sizeof set6
);
724 static void setcontrast(struct gspca_dev
*gspca_dev
)
726 struct sd
*sd
= (struct sd
*) gspca_dev
;
727 unsigned int contrast
= sd
->contrast
;
731 reg_to_write
= 0x8ea9 - contrast
* 0x200;
733 reg_to_write
= 0x00a9 + (contrast
- 7) * 0x200;
735 reg_w(gspca_dev
, reg_to_write
);
738 static void setcolors(struct gspca_dev
*gspca_dev
)
740 struct sd
*sd
= (struct sd
*) gspca_dev
;
743 reg_to_write
= 0x80bb + sd
->colors
* 0x100; /* was 0xc0 */
744 reg_w(gspca_dev
, reg_to_write
);
747 static void setgamma(struct gspca_dev
*gspca_dev
)
749 struct sd
*sd
= (struct sd
*) gspca_dev
;
751 PDEBUG(D_CONF
, "Gamma: %d", sd
->gamma
);
752 reg_w_ixbuf(gspca_dev
, 0x90,
753 gamma_table
[sd
->gamma
], sizeof gamma_table
[0]);
756 static void setRGB(struct gspca_dev
*gspca_dev
)
758 struct sd
*sd
= (struct sd
*) gspca_dev
;
760 {0x87, 0x00, 0x88, 0x00, 0x89, 0x00};
762 all_gain_reg
[1] = sd
->red_gain
;
763 all_gain_reg
[3] = sd
->blue_gain
;
764 all_gain_reg
[5] = sd
->green_gain
;
765 reg_w_buf(gspca_dev
, all_gain_reg
, sizeof all_gain_reg
);
768 /* Generic fnc for r/b balance, exposure and awb */
769 static void setawb(struct gspca_dev
*gspca_dev
)
771 struct sd
*sd
= (struct sd
*) gspca_dev
;
774 reg80
= (sensor_data
[sd
->sensor
].reg80
<< 8) | 0x80;
776 /* on awb leave defaults values */
778 /* shoud we wait here.. */
779 /* update and reset RGB gains with webcam values */
780 sd
->red_gain
= reg_r(gspca_dev
, 0x0087);
781 sd
->blue_gain
= reg_r(gspca_dev
, 0x0088);
782 sd
->green_gain
= reg_r(gspca_dev
, 0x0089);
783 reg80
&= ~0x0400; /* AWB off */
785 reg_w(gspca_dev
, reg80
);
786 reg_w(gspca_dev
, reg80
);
789 static void init_gains(struct gspca_dev
*gspca_dev
)
791 struct sd
*sd
= (struct sd
*) gspca_dev
;
794 {0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00};
796 all_gain_reg
[1] = sd
->red_gain
;
797 all_gain_reg
[3] = sd
->blue_gain
;
798 all_gain_reg
[5] = sd
->green_gain
;
799 reg80
= sensor_data
[sd
->sensor
].reg80
;
802 all_gain_reg
[7] = reg80
;
803 reg_w_buf(gspca_dev
, all_gain_reg
, sizeof all_gain_reg
);
805 reg_w(gspca_dev
, (sd
->red_gain
<< 8) + 0x87);
806 reg_w(gspca_dev
, (sd
->blue_gain
<< 8) + 0x88);
807 reg_w(gspca_dev
, (sd
->green_gain
<< 8) + 0x89);
810 static void setsharpness(struct gspca_dev
*gspca_dev
)
812 struct sd
*sd
= (struct sd
*) gspca_dev
;
815 reg_to_write
= 0x0aa6 + 0x1000 * sd
->sharpness
;
817 reg_w(gspca_dev
, reg_to_write
);
820 static void setfreq(struct gspca_dev
*gspca_dev
)
822 struct sd
*sd
= (struct sd
*) gspca_dev
;
824 u8 freq
[4] = { 0x66, 0x00, 0xa8, 0xe8 };
826 switch (sd
->sensor
) {
840 case 0: /* no flicker */
849 reg_w_buf(gspca_dev
, freq
, sizeof freq
);
852 /* this function is called at probe and resume time */
853 static int sd_init(struct gspca_dev
*gspca_dev
)
855 /* some of this registers are not really neded, because
856 * they are overriden by setbrigthness, setcontrast, etc,
857 * but wont hurt anyway, and can help someone with similar webcam
858 * to see the initial parameters.*/
859 struct sd
*sd
= (struct sd
*) gspca_dev
;
860 const struct additional_sensor_data
*sensor
;
865 static const u8 read_indexs
[] =
866 { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
867 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
868 static const u8 n1
[] =
869 {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
870 static const u8 n2
[] =
873 sensor_id
= (reg_r(gspca_dev
, 0x06) << 8)
874 | reg_r(gspca_dev
, 0x07);
875 switch (sensor_id
& 0xff0f) {
877 PDEBUG(D_PROBE
, "sensor tas5130a");
878 sd
->sensor
= SENSOR_TAS5130A
;
881 PDEBUG(D_PROBE
, "sensor lt168g");
882 sd
->sensor
= SENSOR_LT168G
;
885 PDEBUG(D_PROBE
, "sensor 'other'");
886 sd
->sensor
= SENSOR_OTHER
;
889 PDEBUG(D_PROBE
, "sensor om6802");
890 sd
->sensor
= SENSOR_OM6802
;
893 err("unknown sensor %04x", sensor_id
);
897 if (sd
->sensor
== SENSOR_OM6802
) {
898 reg_w_buf(gspca_dev
, n1
, sizeof n1
);
901 reg_w_buf(gspca_dev
, sensor_reset
, sizeof sensor_reset
);
902 test_byte
= reg_r(gspca_dev
, 0x0063);
904 if (test_byte
== 0x17)
908 err("Bad sensor reset %02x", test_byte
);
911 reg_w_buf(gspca_dev
, n2
, sizeof n2
);
915 while (read_indexs
[i
] != 0x00) {
916 test_byte
= reg_r(gspca_dev
, read_indexs
[i
]);
917 PDEBUG(D_STREAM
, "Reg 0x%02x = 0x%02x", read_indexs
[i
],
922 sensor
= &sensor_data
[sd
->sensor
];
923 reg_w_buf(gspca_dev
, sensor
->n3
, sizeof sensor
->n3
);
924 reg_w_buf(gspca_dev
, sensor
->n4
, sensor
->n4sz
);
926 if (sd
->sensor
== SENSOR_LT168G
) {
927 test_byte
= reg_r(gspca_dev
, 0x80);
928 PDEBUG(D_STREAM
, "Reg 0x%02x = 0x%02x", 0x80,
930 reg_w(gspca_dev
, 0x6c80);
933 reg_w_ixbuf(gspca_dev
, 0xd0, sensor
->data1
, sizeof sensor
->data1
);
934 reg_w_ixbuf(gspca_dev
, 0xc7, sensor
->data2
, sizeof sensor
->data2
);
935 reg_w_ixbuf(gspca_dev
, 0xe0, sensor
->data3
, sizeof sensor
->data3
);
937 reg_w(gspca_dev
, (sensor
->reg80
<< 8) + 0x80);
938 reg_w(gspca_dev
, (sensor
->reg80
<< 8) + 0x80);
939 reg_w(gspca_dev
, (sensor
->reg8e
<< 8) + 0x8e);
941 setbrightness(gspca_dev
);
942 setcontrast(gspca_dev
);
944 setcolors(gspca_dev
);
945 setsharpness(gspca_dev
);
946 init_gains(gspca_dev
);
949 reg_w_buf(gspca_dev
, sensor
->data5
, sizeof sensor
->data5
);
950 reg_w_buf(gspca_dev
, sensor
->nset8
, sizeof sensor
->nset8
);
951 reg_w_buf(gspca_dev
, sensor
->stream
, sizeof sensor
->stream
);
953 if (sd
->sensor
== SENSOR_LT168G
) {
954 test_byte
= reg_r(gspca_dev
, 0x80);
955 PDEBUG(D_STREAM
, "Reg 0x%02x = 0x%02x", 0x80,
957 reg_w(gspca_dev
, 0x6c80);
960 reg_w_ixbuf(gspca_dev
, 0xd0, sensor
->data1
, sizeof sensor
->data1
);
961 reg_w_ixbuf(gspca_dev
, 0xc7, sensor
->data2
, sizeof sensor
->data2
);
962 reg_w_ixbuf(gspca_dev
, 0xe0, sensor
->data3
, sizeof sensor
->data3
);
967 static void setmirror(struct gspca_dev
*gspca_dev
)
969 struct sd
*sd
= (struct sd
*) gspca_dev
;
971 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
976 reg_w_buf(gspca_dev
, hflipcmd
, sizeof hflipcmd
);
979 static void seteffect(struct gspca_dev
*gspca_dev
)
981 struct sd
*sd
= (struct sd
*) gspca_dev
;
983 reg_w_buf(gspca_dev
, effects_table
[sd
->effect
],
984 sizeof effects_table
[0]);
985 if (sd
->effect
== 1 || sd
->effect
== 5) {
987 "This effect have been disabled for webcam \"safety\"");
991 if (sd
->effect
== 1 || sd
->effect
== 4)
992 reg_w(gspca_dev
, 0x4aa6);
994 reg_w(gspca_dev
, 0xfaa6);
997 /* Is this really needed?
998 * i added some module parameters for test with some users */
999 static void poll_sensor(struct gspca_dev
*gspca_dev
)
1001 static const u8 poll1
[] =
1002 {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
1003 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
1004 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
1006 static const u8 poll2
[] =
1007 {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
1008 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
1009 static const u8 noise03
[] = /* (some differences / ms-drv) */
1010 {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
1011 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
1012 0xc2, 0x80, 0xc3, 0x10};
1014 PDEBUG(D_STREAM
, "[Sensor requires polling]");
1015 reg_w_buf(gspca_dev
, poll1
, sizeof poll1
);
1016 reg_w_buf(gspca_dev
, poll2
, sizeof poll2
);
1017 reg_w_buf(gspca_dev
, noise03
, sizeof noise03
);
1020 static int sd_start(struct gspca_dev
*gspca_dev
)
1022 struct sd
*sd
= (struct sd
*) gspca_dev
;
1023 const struct additional_sensor_data
*sensor
;
1025 u8 t2
[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
1026 static const u8 t3
[] =
1027 { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
1029 mode
= gspca_dev
->cam
.cam_mode
[gspca_dev
->curr_mode
].priv
;
1031 case 0: /* 640x480 (0x00) */
1033 case 1: /* 352x288 */
1036 case 2: /* 320x240 */
1039 case 3: /* 176x144 */
1043 /* case 4: * 160x120 */
1048 switch (sd
->sensor
) {
1050 om6802_sensor_init(gspca_dev
);
1052 case SENSOR_TAS5130A
:
1055 reg_w_buf(gspca_dev
, tas5130a_sensor_init
[i
],
1056 sizeof tas5130a_sensor_init
[0]);
1057 if (i
>= ARRAY_SIZE(tas5130a_sensor_init
) - 1)
1061 reg_w(gspca_dev
, 0x3c80);
1062 /* just in case and to keep sync with logs (for mine) */
1063 reg_w_buf(gspca_dev
, tas5130a_sensor_init
[i
],
1064 sizeof tas5130a_sensor_init
[0]);
1065 reg_w(gspca_dev
, 0x3c80);
1068 sensor
= &sensor_data
[sd
->sensor
];
1070 reg_r(gspca_dev
, 0x0012);
1071 reg_w_buf(gspca_dev
, t2
, sizeof t2
);
1072 reg_w_ixbuf(gspca_dev
, 0xb3, t3
, sizeof t3
);
1073 reg_w(gspca_dev
, 0x0013);
1075 reg_w_buf(gspca_dev
, sensor
->stream
, sizeof sensor
->stream
);
1076 reg_w_buf(gspca_dev
, sensor
->stream
, sizeof sensor
->stream
);
1078 if (sd
->sensor
== SENSOR_OM6802
)
1079 poll_sensor(gspca_dev
);
1084 static void sd_stopN(struct gspca_dev
*gspca_dev
)
1086 struct sd
*sd
= (struct sd
*) gspca_dev
;
1088 reg_w_buf(gspca_dev
, sensor_data
[sd
->sensor
].stream
,
1089 sizeof sensor_data
[sd
->sensor
].stream
);
1090 reg_w_buf(gspca_dev
, sensor_data
[sd
->sensor
].stream
,
1091 sizeof sensor_data
[sd
->sensor
].stream
);
1092 if (sd
->sensor
== SENSOR_OM6802
) {
1094 reg_w(gspca_dev
, 0x0309);
1098 static void sd_pkt_scan(struct gspca_dev
*gspca_dev
,
1099 u8
*data
, /* isoc packet */
1100 int len
) /* iso packet length */
1104 if (data
[0] == 0x5a) {
1105 /* Control Packet, after this came the header again,
1106 * but extra bytes came in the packet before this,
1107 * sometimes an EOF arrives, sometimes not... */
1112 if (data
[0] == 0xff && data
[1] == 0xd8)
1113 pkt_type
= FIRST_PACKET
;
1114 else if (data
[len
- 2] == 0xff && data
[len
- 1] == 0xd9)
1115 pkt_type
= LAST_PACKET
;
1117 pkt_type
= INTER_PACKET
;
1118 gspca_frame_add(gspca_dev
, pkt_type
, data
, len
);
1121 static int sd_setblue_gain(struct gspca_dev
*gspca_dev
, __s32 val
)
1123 struct sd
*sd
= (struct sd
*) gspca_dev
;
1125 sd
->blue_gain
= val
;
1126 if (gspca_dev
->streaming
)
1127 reg_w(gspca_dev
, (val
<< 8) + 0x88);
1131 static int sd_getblue_gain(struct gspca_dev
*gspca_dev
, __s32
*val
)
1133 struct sd
*sd
= (struct sd
*) gspca_dev
;
1135 *val
= sd
->blue_gain
;
1139 static int sd_setred_gain(struct gspca_dev
*gspca_dev
, __s32 val
)
1141 struct sd
*sd
= (struct sd
*) gspca_dev
;
1144 if (gspca_dev
->streaming
)
1145 reg_w(gspca_dev
, (val
<< 8) + 0x87);
1150 static int sd_getred_gain(struct gspca_dev
*gspca_dev
, __s32
*val
)
1152 struct sd
*sd
= (struct sd
*) gspca_dev
;
1154 *val
= sd
->red_gain
;
1158 static int sd_setgain(struct gspca_dev
*gspca_dev
, __s32 val
)
1160 struct sd
*sd
= (struct sd
*) gspca_dev
;
1163 psg
= sd
->red_gain
+ sd
->blue_gain
+ sd
->green_gain
;
1165 sd
->red_gain
= sd
->red_gain
* nsg
/ psg
;
1166 if (sd
->red_gain
> 0x40)
1167 sd
->red_gain
= 0x40;
1168 else if (sd
->red_gain
< 0x10)
1169 sd
->red_gain
= 0x10;
1170 sd
->blue_gain
= sd
->blue_gain
* nsg
/ psg
;
1171 if (sd
->blue_gain
> 0x40)
1172 sd
->blue_gain
= 0x40;
1173 else if (sd
->blue_gain
< 0x10)
1174 sd
->blue_gain
= 0x10;
1175 sd
->green_gain
= sd
->green_gain
* nsg
/ psg
;
1176 if (sd
->green_gain
> 0x40)
1177 sd
->green_gain
= 0x40;
1178 else if (sd
->green_gain
< 0x10)
1179 sd
->green_gain
= 0x10;
1181 if (gspca_dev
->streaming
)
1186 static int sd_getgain(struct gspca_dev
*gspca_dev
, __s32
*val
)
1188 struct sd
*sd
= (struct sd
*) gspca_dev
;
1190 *val
= (sd
->red_gain
+ sd
->blue_gain
+ sd
->green_gain
) / 3;
1194 static int sd_setbrightness(struct gspca_dev
*gspca_dev
, __s32 val
)
1196 struct sd
*sd
= (struct sd
*) gspca_dev
;
1198 sd
->brightness
= val
;
1199 if (gspca_dev
->streaming
)
1200 setbrightness(gspca_dev
);
1204 static int sd_getbrightness(struct gspca_dev
*gspca_dev
, __s32
*val
)
1206 struct sd
*sd
= (struct sd
*) gspca_dev
;
1208 *val
= sd
->brightness
;
1212 static int sd_setawb(struct gspca_dev
*gspca_dev
, __s32 val
)
1214 struct sd
*sd
= (struct sd
*) gspca_dev
;
1217 if (gspca_dev
->streaming
)
1222 static int sd_getawb(struct gspca_dev
*gspca_dev
, __s32
*val
)
1224 struct sd
*sd
= (struct sd
*) gspca_dev
;
1230 static int sd_setmirror(struct gspca_dev
*gspca_dev
, __s32 val
)
1232 struct sd
*sd
= (struct sd
*) gspca_dev
;
1235 if (gspca_dev
->streaming
)
1236 setmirror(gspca_dev
);
1240 static int sd_getmirror(struct gspca_dev
*gspca_dev
, __s32
*val
)
1242 struct sd
*sd
= (struct sd
*) gspca_dev
;
1248 static int sd_seteffect(struct gspca_dev
*gspca_dev
, __s32 val
)
1250 struct sd
*sd
= (struct sd
*) gspca_dev
;
1253 if (gspca_dev
->streaming
)
1254 seteffect(gspca_dev
);
1258 static int sd_geteffect(struct gspca_dev
*gspca_dev
, __s32
*val
)
1260 struct sd
*sd
= (struct sd
*) gspca_dev
;
1266 static int sd_setcontrast(struct gspca_dev
*gspca_dev
, __s32 val
)
1268 struct sd
*sd
= (struct sd
*) gspca_dev
;
1271 if (gspca_dev
->streaming
)
1272 setcontrast(gspca_dev
);
1276 static int sd_getcontrast(struct gspca_dev
*gspca_dev
, __s32
*val
)
1278 struct sd
*sd
= (struct sd
*) gspca_dev
;
1280 *val
= sd
->contrast
;
1284 static int sd_setcolors(struct gspca_dev
*gspca_dev
, __s32 val
)
1286 struct sd
*sd
= (struct sd
*) gspca_dev
;
1289 if (gspca_dev
->streaming
)
1290 setcolors(gspca_dev
);
1294 static int sd_getcolors(struct gspca_dev
*gspca_dev
, __s32
*val
)
1296 struct sd
*sd
= (struct sd
*) gspca_dev
;
1302 static int sd_setgamma(struct gspca_dev
*gspca_dev
, __s32 val
)
1304 struct sd
*sd
= (struct sd
*) gspca_dev
;
1307 if (gspca_dev
->streaming
)
1308 setgamma(gspca_dev
);
1312 static int sd_getgamma(struct gspca_dev
*gspca_dev
, __s32
*val
)
1314 struct sd
*sd
= (struct sd
*) gspca_dev
;
1320 static int sd_setfreq(struct gspca_dev
*gspca_dev
, __s32 val
)
1322 struct sd
*sd
= (struct sd
*) gspca_dev
;
1325 if (gspca_dev
->streaming
)
1330 static int sd_getfreq(struct gspca_dev
*gspca_dev
, __s32
*val
)
1332 struct sd
*sd
= (struct sd
*) gspca_dev
;
1338 static int sd_setsharpness(struct gspca_dev
*gspca_dev
, __s32 val
)
1340 struct sd
*sd
= (struct sd
*) gspca_dev
;
1342 sd
->sharpness
= val
;
1343 if (gspca_dev
->streaming
)
1344 setsharpness(gspca_dev
);
1348 static int sd_getsharpness(struct gspca_dev
*gspca_dev
, __s32
*val
)
1350 struct sd
*sd
= (struct sd
*) gspca_dev
;
1352 *val
= sd
->sharpness
;
1356 /* Low Light set here......*/
1357 static int sd_setlowlight(struct gspca_dev
*gspca_dev
, __s32 val
)
1359 struct sd
*sd
= (struct sd
*) gspca_dev
;
1363 reg_w(gspca_dev
, 0xf48e);
1365 reg_w(gspca_dev
, 0xb48e);
1369 static int sd_getlowlight(struct gspca_dev
*gspca_dev
, __s32
*val
)
1371 struct sd
*sd
= (struct sd
*) gspca_dev
;
1373 *val
= sd
->autogain
;
1377 static int sd_querymenu(struct gspca_dev
*gspca_dev
,
1378 struct v4l2_querymenu
*menu
)
1380 static const char *freq_nm
[3] = {"NoFliker", "50 Hz", "60 Hz"};
1383 case V4L2_CID_POWER_LINE_FREQUENCY
:
1384 if ((unsigned) menu
->index
>= ARRAY_SIZE(freq_nm
))
1386 strcpy((char *) menu
->name
, freq_nm
[menu
->index
]);
1388 case V4L2_CID_EFFECTS
:
1389 if ((unsigned) menu
->index
< ARRAY_SIZE(effects_control
)) {
1390 strlcpy((char *) menu
->name
,
1391 effects_control
[menu
->index
],
1400 /* sub-driver description */
1401 static const struct sd_desc sd_desc
= {
1402 .name
= MODULE_NAME
,
1404 .nctrls
= ARRAY_SIZE(sd_ctrls
),
1405 .config
= sd_config
,
1409 .pkt_scan
= sd_pkt_scan
,
1410 .querymenu
= sd_querymenu
,
1413 /* -- module initialisation -- */
1414 static const struct usb_device_id device_table
[] = {
1415 {USB_DEVICE(0x17a1, 0x0128)},
1418 MODULE_DEVICE_TABLE(usb
, device_table
);
1420 /* -- device connect -- */
1421 static int sd_probe(struct usb_interface
*intf
,
1422 const struct usb_device_id
*id
)
1424 return gspca_dev_probe(intf
, id
, &sd_desc
, sizeof(struct sd
),
1428 static struct usb_driver sd_driver
= {
1429 .name
= MODULE_NAME
,
1430 .id_table
= device_table
,
1432 .disconnect
= gspca_disconnect
,
1434 .suspend
= gspca_suspend
,
1435 .resume
= gspca_resume
,
1439 /* -- module insert / remove -- */
1440 static int __init
sd_mod_init(void)
1442 return usb_register(&sd_driver
);
1444 static void __exit
sd_mod_exit(void)
1446 usb_deregister(&sd_driver
);
1449 module_init(sd_mod_init
);
1450 module_exit(sd_mod_exit
);