Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6] / drivers / media / video / gspca / pac207.c
1 /*
2  * Pixart PAC207BCA library
3  *
4  * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
5  * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
6  * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
7  *
8  * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  */
25
26 #define MODULE_NAME "pac207"
27
28 #include "gspca.h"
29
30 #define DRIVER_VERSION_NUMBER   KERNEL_VERSION(2, 1, 7)
31 static const char version[] = "2.1.7";
32
33 MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
34 MODULE_DESCRIPTION("Pixart PAC207");
35 MODULE_LICENSE("GPL");
36
37 #define PAC207_CTRL_TIMEOUT             100  /* ms */
38
39 #define PAC207_BRIGHTNESS_MIN           0
40 #define PAC207_BRIGHTNESS_MAX           255
41 #define PAC207_BRIGHTNESS_DEFAULT       4 /* power on default: 4 */
42
43 /* An exposure value of 4 also works (3 does not) but then we need to lower
44    the compression balance setting when in 352x288 mode, otherwise the usb
45    bandwidth is not enough and packets get dropped resulting in corrupt
46    frames. The problem with this is that when the compression balance gets
47    lowered below 0x80, the pac207 starts using a different compression
48    algorithm for some lines, these lines get prefixed with a 0x2dd2 prefix
49    and currently we do not know how to decompress these lines, so for now
50    we use a minimum exposure value of 5 */
51 #define PAC207_EXPOSURE_MIN             5
52 #define PAC207_EXPOSURE_MAX             26
53 #define PAC207_EXPOSURE_DEFAULT         5 /* power on default: 3 ?? */
54 #define PAC207_EXPOSURE_KNEE            11 /* 4 = 30 fps, 11 = 8, 15 = 6 */
55
56 #define PAC207_GAIN_MIN                 0
57 #define PAC207_GAIN_MAX                 31
58 #define PAC207_GAIN_DEFAULT             9 /* power on default: 9 */
59 #define PAC207_GAIN_KNEE                20
60
61 #define PAC207_AUTOGAIN_DEADZONE        30
62 /* We calculating the autogain at the end of the transfer of a frame, at this
63    moment a frame with the old settings is being transmitted, and a frame is
64    being captured with the old settings. So if we adjust the autogain we must
65    ignore atleast the 2 next frames for the new settings to come into effect
66    before doing any other adjustments */
67 #define PAC207_AUTOGAIN_IGNORE_FRAMES   3
68
69 /* specific webcam descriptor */
70 struct sd {
71         struct gspca_dev gspca_dev;             /* !! must be the first item */
72
73         u8 mode;
74
75         u8 brightness;
76         u8 exposure;
77         u8 autogain;
78         u8 gain;
79
80         u8 sof_read;
81         u8 header_read;
82         u8 autogain_ignore_frames;
83
84         atomic_t avg_lum;
85 };
86
87 /* V4L2 controls supported by the driver */
88 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
89 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
90 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
91 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
92 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
93 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
94 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
95 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
96
97 static struct ctrl sd_ctrls[] = {
98 #define SD_BRIGHTNESS 0
99         {
100             {
101                 .id      = V4L2_CID_BRIGHTNESS,
102                 .type    = V4L2_CTRL_TYPE_INTEGER,
103                 .name    = "Brightness",
104                 .minimum = PAC207_BRIGHTNESS_MIN,
105                 .maximum = PAC207_BRIGHTNESS_MAX,
106                 .step = 1,
107                 .default_value = PAC207_BRIGHTNESS_DEFAULT,
108                 .flags = 0,
109             },
110             .set = sd_setbrightness,
111             .get = sd_getbrightness,
112         },
113 #define SD_EXPOSURE 1
114         {
115             {
116                 .id = V4L2_CID_EXPOSURE,
117                 .type = V4L2_CTRL_TYPE_INTEGER,
118                 .name = "exposure",
119                 .minimum = PAC207_EXPOSURE_MIN,
120                 .maximum = PAC207_EXPOSURE_MAX,
121                 .step = 1,
122                 .default_value = PAC207_EXPOSURE_DEFAULT,
123                 .flags = 0,
124             },
125             .set = sd_setexposure,
126             .get = sd_getexposure,
127         },
128 #define SD_AUTOGAIN 2
129         {
130             {
131                 .id       = V4L2_CID_AUTOGAIN,
132                 .type   = V4L2_CTRL_TYPE_BOOLEAN,
133                 .name   = "Auto Gain",
134                 .minimum = 0,
135                 .maximum = 1,
136                 .step   = 1,
137                 .default_value = 1,
138                 .flags = 0,
139             },
140             .set = sd_setautogain,
141             .get = sd_getautogain,
142         },
143 #define SD_GAIN 3
144         {
145             {
146                 .id = V4L2_CID_GAIN,
147                 .type = V4L2_CTRL_TYPE_INTEGER,
148                 .name = "gain",
149                 .minimum = PAC207_GAIN_MIN,
150                 .maximum = PAC207_GAIN_MAX,
151                 .step = 1,
152                 .default_value = PAC207_GAIN_DEFAULT,
153                 .flags = 0,
154             },
155             .set = sd_setgain,
156             .get = sd_getgain,
157         },
158 };
159
160 static struct v4l2_pix_format sif_mode[] = {
161         {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
162                 .bytesperline = 176,
163                 .sizeimage = (176 + 2) * 144,
164                         /* uncompressed, add 2 bytes / line for line header */
165                 .colorspace = V4L2_COLORSPACE_SRGB,
166                 .priv = 1},
167         {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
168                 .bytesperline = 352,
169                         /* compressed, but only when needed (not compressed
170                            when the framerate is low) */
171                 .sizeimage = (352 + 2) * 288,
172                 .colorspace = V4L2_COLORSPACE_SRGB,
173                 .priv = 0},
174 };
175
176 static const __u8 pac207_sensor_init[][8] = {
177         {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
178         {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
179         {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
180         {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
181         {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
182 };
183
184                         /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
185 static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
186
187 static const unsigned char pac207_sof_marker[5] =
188                 { 0xff, 0xff, 0x00, 0xff, 0x96 };
189
190 static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
191         const u8 *buffer, u16 length)
192 {
193         struct usb_device *udev = gspca_dev->dev;
194         int err;
195
196         memcpy(gspca_dev->usb_buf, buffer, length);
197
198         err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
199                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
200                         0x00, index,
201                         gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
202         if (err < 0)
203                 PDEBUG(D_ERR,
204                         "Failed to write registers to index 0x%04X, error %d)",
205                         index, err);
206
207         return err;
208 }
209
210
211 int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
212 {
213         struct usb_device *udev = gspca_dev->dev;
214         int err;
215
216         err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
217                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
218                         value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
219         if (err)
220                 PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
221                         " value 0x%02X, error %d)", index, value, err);
222
223         return err;
224 }
225
226
227 int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
228 {
229         struct usb_device *udev = gspca_dev->dev;
230         int res;
231
232         res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
233                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
234                         0x00, index,
235                         gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
236         if (res < 0) {
237                 PDEBUG(D_ERR,
238                         "Failed to read a register (index 0x%04X, error %d)",
239                         index, res);
240                 return res;
241         }
242
243         return gspca_dev->usb_buf[0];
244 }
245
246 /* this function is called at probe time */
247 static int sd_config(struct gspca_dev *gspca_dev,
248                         const struct usb_device_id *id)
249 {
250         struct sd *sd = (struct sd *) gspca_dev;
251         struct cam *cam;
252         u8 idreg[2];
253
254         idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
255         idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
256         idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
257         idreg[1] = idreg[1] & 0x0f;
258         PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
259                 idreg[0], idreg[1]);
260
261         if (idreg[0] != 0x27) {
262                 PDEBUG(D_PROBE, "Error invalid sensor ID!");
263                 return -ENODEV;
264         }
265
266         pac207_write_reg(gspca_dev, 0x41, 0x00);
267                                 /* Bit_0=Image Format,
268                                  * Bit_1=LED,
269                                  * Bit_2=Compression test mode enable */
270         pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
271         pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
272
273         PDEBUG(D_PROBE,
274                 "Pixart PAC207BCA Image Processor and Control Chip detected"
275                 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
276
277         cam = &gspca_dev->cam;
278         cam->dev_name = (char *) id->driver_info;
279         cam->epaddr = 0x05;
280         cam->cam_mode = sif_mode;
281         cam->nmodes = ARRAY_SIZE(sif_mode);
282         sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
283         sd->exposure = PAC207_EXPOSURE_DEFAULT;
284         sd->gain = PAC207_GAIN_DEFAULT;
285
286         return 0;
287 }
288
289 /* this function is called at open time */
290 static int sd_open(struct gspca_dev *gspca_dev)
291 {
292         struct sd *sd = (struct sd *) gspca_dev;
293
294         sd->autogain = 1;
295         return 0;
296 }
297
298 /* -- start the camera -- */
299 static void sd_start(struct gspca_dev *gspca_dev)
300 {
301         struct sd *sd = (struct sd *) gspca_dev;
302         __u8 mode;
303
304         pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
305         pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
306         pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
307         pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
308         pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
309         pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
310         pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
311
312         /* Compression Balance */
313         if (gspca_dev->width == 176)
314                 pac207_write_reg(gspca_dev, 0x4a, 0xff);
315         else
316                 pac207_write_reg(gspca_dev, 0x4a, 0x88);
317         pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
318         pac207_write_reg(gspca_dev, 0x08, sd->brightness);
319
320         /* PGA global gain (Bit 4-0) */
321         pac207_write_reg(gspca_dev, 0x0e, sd->gain);
322         pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
323
324         mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
325         if (gspca_dev->width == 176) {  /* 176x144 */
326                 mode |= 0x01;
327                 PDEBUG(D_STREAM, "pac207_start mode 176x144");
328         } else {                                /* 352x288 */
329                 PDEBUG(D_STREAM, "pac207_start mode 352x288");
330         }
331         pac207_write_reg(gspca_dev, 0x41, mode);
332
333         pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
334         pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
335         msleep(10);
336         pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
337
338         sd->sof_read = 0;
339         sd->autogain_ignore_frames = 0;
340         atomic_set(&sd->avg_lum, -1);
341 }
342
343 static void sd_stopN(struct gspca_dev *gspca_dev)
344 {
345         pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
346         pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
347         pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
348 }
349
350 static void sd_stop0(struct gspca_dev *gspca_dev)
351 {
352 }
353
354 /* this function is called at close time */
355 static void sd_close(struct gspca_dev *gspca_dev)
356 {
357 }
358
359 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
360 {
361         struct sd *sd = (struct sd *) gspca_dev;
362         int avg_lum = atomic_read(&sd->avg_lum);
363
364         if (avg_lum == -1)
365                 return;
366
367         if (sd->autogain_ignore_frames > 0)
368                 sd->autogain_ignore_frames--;
369         else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
370                         100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
371                         PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
372                 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
373 }
374
375 static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
376                                         unsigned char *m, int len)
377 {
378         struct sd *sd = (struct sd *) gspca_dev;
379         int i;
380
381         /* Search for the SOF marker (fixed part) in the header */
382         for (i = 0; i < len; i++) {
383                 if (m[i] == pac207_sof_marker[sd->sof_read]) {
384                         sd->sof_read++;
385                         if (sd->sof_read == sizeof(pac207_sof_marker)) {
386                                 PDEBUG(D_STREAM,
387                                         "SOF found, bytes to analyze: %u."
388                                         " Frame starts at byte #%u",
389                                         len, i + 1);
390                                 sd->sof_read = 0;
391                                 return m + i + 1;
392                         }
393                 } else {
394                         sd->sof_read = 0;
395                 }
396         }
397
398         return NULL;
399 }
400
401 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
402                         struct gspca_frame *frame,
403                         __u8 *data,
404                         int len)
405 {
406         struct sd *sd = (struct sd *) gspca_dev;
407         unsigned char *sof;
408
409         sof = pac207_find_sof(gspca_dev, data, len);
410         if (sof) {
411                 int n;
412
413                 /* finish decoding current frame */
414                 n = sof - data;
415                 if (n > sizeof pac207_sof_marker)
416                         n -= sizeof pac207_sof_marker;
417                 else
418                         n = 0;
419                 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
420                                         data, n);
421                 sd->header_read = 0;
422                 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
423                 len -= sof - data;
424                 data = sof;
425         }
426         if (sd->header_read < 11) {
427                 int needed;
428
429                 /* get average lumination from frame header (byte 5) */
430                 if (sd->header_read < 5) {
431                         needed = 5 - sd->header_read;
432                         if (len >= needed)
433                                 atomic_set(&sd->avg_lum, data[needed - 1]);
434                 }
435                 /* skip the rest of the header */
436                 needed = 11 - sd->header_read;
437                 if (len <= needed) {
438                         sd->header_read += len;
439                         return;
440                 }
441                 data += needed;
442                 len -= needed;
443                 sd->header_read = 11;
444         }
445
446         gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
447 }
448
449 static void setbrightness(struct gspca_dev *gspca_dev)
450 {
451         struct sd *sd = (struct sd *) gspca_dev;
452
453         pac207_write_reg(gspca_dev, 0x08, sd->brightness);
454         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
455         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
456 }
457
458 static void setexposure(struct gspca_dev *gspca_dev)
459 {
460         struct sd *sd = (struct sd *) gspca_dev;
461
462         pac207_write_reg(gspca_dev, 0x02, sd->exposure);
463         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
464         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
465 }
466
467 static void setgain(struct gspca_dev *gspca_dev)
468 {
469         struct sd *sd = (struct sd *) gspca_dev;
470
471         pac207_write_reg(gspca_dev, 0x0e, sd->gain);
472         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
473         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
474 }
475
476 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
477 {
478         struct sd *sd = (struct sd *) gspca_dev;
479
480         sd->brightness = val;
481         if (gspca_dev->streaming)
482                 setbrightness(gspca_dev);
483         return 0;
484 }
485
486 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
487 {
488         struct sd *sd = (struct sd *) gspca_dev;
489
490         *val = sd->brightness;
491         return 0;
492 }
493
494 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
495 {
496         struct sd *sd = (struct sd *) gspca_dev;
497
498         sd->exposure = val;
499         if (gspca_dev->streaming)
500                 setexposure(gspca_dev);
501         return 0;
502 }
503
504 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
505 {
506         struct sd *sd = (struct sd *) gspca_dev;
507
508         *val = sd->exposure;
509         return 0;
510 }
511
512 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
513 {
514         struct sd *sd = (struct sd *) gspca_dev;
515
516         sd->gain = val;
517         if (gspca_dev->streaming)
518                 setgain(gspca_dev);
519         return 0;
520 }
521
522 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
523 {
524         struct sd *sd = (struct sd *) gspca_dev;
525
526         *val = sd->gain;
527         return 0;
528 }
529
530 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
531 {
532         struct sd *sd = (struct sd *) gspca_dev;
533
534         sd->autogain = val;
535         /* when switching to autogain set defaults to make sure
536            we are on a valid point of the autogain gain /
537            exposure knee graph, and give this change time to
538            take effect before doing autogain. */
539         if (sd->autogain) {
540                 sd->exposure = PAC207_EXPOSURE_DEFAULT;
541                 sd->gain = PAC207_GAIN_DEFAULT;
542                 if (gspca_dev->streaming) {
543                         sd->autogain_ignore_frames =
544                                 PAC207_AUTOGAIN_IGNORE_FRAMES;
545                         setexposure(gspca_dev);
546                         setgain(gspca_dev);
547                 }
548         }
549
550         return 0;
551 }
552
553 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
554 {
555         struct sd *sd = (struct sd *) gspca_dev;
556
557         *val = sd->autogain;
558         return 0;
559 }
560
561 /* sub-driver description */
562 static const struct sd_desc sd_desc = {
563         .name = MODULE_NAME,
564         .ctrls = sd_ctrls,
565         .nctrls = ARRAY_SIZE(sd_ctrls),
566         .config = sd_config,
567         .open = sd_open,
568         .start = sd_start,
569         .stopN = sd_stopN,
570         .stop0 = sd_stop0,
571         .close = sd_close,
572         .dq_callback = pac207_do_auto_gain,
573         .pkt_scan = sd_pkt_scan,
574 };
575
576 /* -- module initialisation -- */
577 #define DVNM(name) .driver_info = (kernel_ulong_t) name
578 static const __devinitdata struct usb_device_id device_table[] = {
579         {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
580         {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")},
581         {USB_DEVICE(0x093a, 0x2463), DVNM("Philips spc200nc pac207")},
582         {USB_DEVICE(0x093a, 0x2464), DVNM("Labtec Webcam 1200")},
583         {USB_DEVICE(0x093a, 0x2468), DVNM("PAC207")},
584         {USB_DEVICE(0x093a, 0x2470), DVNM("Genius GF112")},
585         {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")},
586         {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")},
587         {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")},
588         {}
589 };
590 MODULE_DEVICE_TABLE(usb, device_table);
591
592 /* -- device connect -- */
593 static int sd_probe(struct usb_interface *intf,
594                         const struct usb_device_id *id)
595 {
596         return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
597                                 THIS_MODULE);
598 }
599
600 static struct usb_driver sd_driver = {
601         .name = MODULE_NAME,
602         .id_table = device_table,
603         .probe = sd_probe,
604         .disconnect = gspca_disconnect,
605 };
606
607 /* -- module insert / remove -- */
608 static int __init sd_mod_init(void)
609 {
610         if (usb_register(&sd_driver) < 0)
611                 return -1;
612         PDEBUG(D_PROBE, "v%s registered", version);
613         return 0;
614 }
615 static void __exit sd_mod_exit(void)
616 {
617         usb_deregister(&sd_driver);
618         PDEBUG(D_PROBE, "deregistered");
619 }
620
621 module_init(sd_mod_init);
622 module_exit(sd_mod_exit);