5d68d3f42262990786fa0465a115ce6901b2c5b6
[linux-2.6.git] / 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, 5)
31 static const char version[] = "2.1.5";
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 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         u8 kbuf[8];
196
197         memcpy(kbuf, buffer, length);
198
199         err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
200                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
201                         0x00, index, kbuf, 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         u8 buff;
231         int res;
232
233         res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
234                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
235                         0x00, index, &buff, 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 buff;
244 }
245
246
247 /* this function is called at probe time */
248 static int sd_config(struct gspca_dev *gspca_dev,
249                         const struct usb_device_id *id)
250 {
251         struct sd *sd = (struct sd *) gspca_dev;
252         struct cam *cam;
253         u8 idreg[2];
254
255         idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
256         idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
257         idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
258         idreg[1] = idreg[1] & 0x0f;
259         PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
260                 idreg[0], idreg[1]);
261
262         if (idreg[0] != 0x27) {
263                 PDEBUG(D_PROBE, "Error invalid sensor ID!");
264                 return -ENODEV;
265         }
266
267         pac207_write_reg(gspca_dev, 0x41, 0x00);
268                                 /* Bit_0=Image Format,
269                                  * Bit_1=LED,
270                                  * Bit_2=Compression test mode enable */
271         pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
272         pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
273
274         PDEBUG(D_PROBE,
275                 "Pixart PAC207BCA Image Processor and Control Chip detected"
276                 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
277
278         cam = &gspca_dev->cam;
279         cam->dev_name = (char *) id->driver_info;
280         cam->epaddr = 0x05;
281         cam->cam_mode = sif_mode;
282         cam->nmodes = ARRAY_SIZE(sif_mode);
283         sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
284         sd->exposure = PAC207_EXPOSURE_DEFAULT;
285         sd->gain = PAC207_GAIN_DEFAULT;
286
287         return 0;
288 }
289
290 /* this function is called at open time */
291 static int sd_open(struct gspca_dev *gspca_dev)
292 {
293         struct sd *sd = (struct sd *) gspca_dev;
294
295         sd->autogain = 1;
296         return 0;
297 }
298
299 /* -- start the camera -- */
300 static void sd_start(struct gspca_dev *gspca_dev)
301 {
302         struct sd *sd = (struct sd *) gspca_dev;
303         __u8 mode;
304
305         pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
306         pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
307         pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
308         pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
309         pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
310         pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
311         pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
312
313         /* Compression Balance */
314         if (gspca_dev->width == 176)
315                 pac207_write_reg(gspca_dev, 0x4a, 0xff);
316         else
317                 pac207_write_reg(gspca_dev, 0x4a, 0x88);
318         pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
319         pac207_write_reg(gspca_dev, 0x08, sd->brightness);
320
321         /* PGA global gain (Bit 4-0) */
322         pac207_write_reg(gspca_dev, 0x0e, sd->gain);
323         pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
324
325         mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
326         if (gspca_dev->width == 176) {  /* 176x144 */
327                 mode |= 0x01;
328                 PDEBUG(D_STREAM, "pac207_start mode 176x144");
329         } else {                                /* 352x288 */
330                 PDEBUG(D_STREAM, "pac207_start mode 352x288");
331         }
332         pac207_write_reg(gspca_dev, 0x41, mode);
333
334         pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
335         pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
336         msleep(10);
337         pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
338
339         sd->sof_read = 0;
340         sd->autogain_ignore_frames = 0;
341         atomic_set(&sd->avg_lum, -1);
342 }
343
344 static void sd_stopN(struct gspca_dev *gspca_dev)
345 {
346         pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
347         pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
348         pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
349 }
350
351 static void sd_stop0(struct gspca_dev *gspca_dev)
352 {
353 }
354
355 /* this function is called at close time */
356 static void sd_close(struct gspca_dev *gspca_dev)
357 {
358 }
359
360 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
361 {
362         struct sd *sd = (struct sd *) gspca_dev;
363         int avg_lum = atomic_read(&sd->avg_lum);
364
365         if (avg_lum == -1)
366                 return;
367
368         if (sd->autogain_ignore_frames > 0)
369                 sd->autogain_ignore_frames--;
370         else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
371                         100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
372                         PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
373                 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
374 }
375
376 static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
377                                         unsigned char *m, int len)
378 {
379         struct sd *sd = (struct sd *) gspca_dev;
380         int i;
381
382         /* Search for the SOF marker (fixed part) in the header */
383         for (i = 0; i < len; i++) {
384                 if (m[i] == pac207_sof_marker[sd->sof_read]) {
385                         sd->sof_read++;
386                         if (sd->sof_read == sizeof(pac207_sof_marker)) {
387                                 PDEBUG(D_STREAM,
388                                         "SOF found, bytes to analyze: %u."
389                                         " Frame starts at byte #%u",
390                                         len, i + 1);
391                                 sd->sof_read = 0;
392                                 return m + i + 1;
393                         }
394                 } else {
395                         sd->sof_read = 0;
396                 }
397         }
398
399         return NULL;
400 }
401
402 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
403                         struct gspca_frame *frame,
404                         __u8 *data,
405                         int len)
406 {
407         struct sd *sd = (struct sd *) gspca_dev;
408         unsigned char *sof;
409
410         sof = pac207_find_sof(gspca_dev, data, len);
411         if (sof) {
412                 int n;
413
414                 /* finish decoding current frame */
415                 n = sof - data;
416                 if (n > sizeof pac207_sof_marker)
417                         n -= sizeof pac207_sof_marker;
418                 else
419                         n = 0;
420                 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
421                                         data, n);
422                 sd->header_read = 0;
423                 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
424                 len -= sof - data;
425                 data = sof;
426         }
427         if (sd->header_read < 11) {
428                 int needed;
429
430                 /* get average lumination from frame header (byte 5) */
431                 if (sd->header_read < 5) {
432                         needed = 5 - sd->header_read;
433                         if (len >= needed)
434                                 atomic_set(&sd->avg_lum, data[needed - 1]);
435                 }
436                 /* skip the rest of the header */
437                 needed = 11 - sd->header_read;
438                 if (len <= needed) {
439                         sd->header_read += len;
440                         return;
441                 }
442                 data += needed;
443                 len -= needed;
444                 sd->header_read = 11;
445         }
446
447         gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
448 }
449
450 static void setbrightness(struct gspca_dev *gspca_dev)
451 {
452         struct sd *sd = (struct sd *) gspca_dev;
453
454         pac207_write_reg(gspca_dev, 0x08, sd->brightness);
455         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
456         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
457 }
458
459 static void setexposure(struct gspca_dev *gspca_dev)
460 {
461         struct sd *sd = (struct sd *) gspca_dev;
462
463         pac207_write_reg(gspca_dev, 0x02, sd->exposure);
464         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
465         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
466 }
467
468 static void setgain(struct gspca_dev *gspca_dev)
469 {
470         struct sd *sd = (struct sd *) gspca_dev;
471
472         pac207_write_reg(gspca_dev, 0x0e, sd->gain);
473         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
474         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
475 }
476
477 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
478 {
479         struct sd *sd = (struct sd *) gspca_dev;
480
481         sd->brightness = val;
482         if (gspca_dev->streaming)
483                 setbrightness(gspca_dev);
484         return 0;
485 }
486
487 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
488 {
489         struct sd *sd = (struct sd *) gspca_dev;
490
491         *val = sd->brightness;
492         return 0;
493 }
494
495 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
496 {
497         struct sd *sd = (struct sd *) gspca_dev;
498
499         sd->exposure = val;
500         if (gspca_dev->streaming)
501                 setexposure(gspca_dev);
502         return 0;
503 }
504
505 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
506 {
507         struct sd *sd = (struct sd *) gspca_dev;
508
509         *val = sd->exposure;
510         return 0;
511 }
512
513 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
514 {
515         struct sd *sd = (struct sd *) gspca_dev;
516
517         sd->gain = val;
518         if (gspca_dev->streaming)
519                 setgain(gspca_dev);
520         return 0;
521 }
522
523 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
524 {
525         struct sd *sd = (struct sd *) gspca_dev;
526
527         *val = sd->gain;
528         return 0;
529 }
530
531 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
532 {
533         struct sd *sd = (struct sd *) gspca_dev;
534
535         sd->autogain = val;
536         /* when switching to autogain set defaults to make sure
537            we are on a valid point of the autogain gain /
538            exposure knee graph, and give this change time to
539            take effect before doing autogain. */
540         if (sd->autogain) {
541                 sd->exposure = PAC207_EXPOSURE_DEFAULT;
542                 sd->gain = PAC207_GAIN_DEFAULT;
543                 if (gspca_dev->streaming) {
544                         sd->autogain_ignore_frames =
545                                 PAC207_AUTOGAIN_IGNORE_FRAMES;
546                         setexposure(gspca_dev);
547                         setgain(gspca_dev);
548                 }
549         }
550
551         return 0;
552 }
553
554 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
555 {
556         struct sd *sd = (struct sd *) gspca_dev;
557
558         *val = sd->autogain;
559         return 0;
560 }
561
562 /* sub-driver description */
563 static const struct sd_desc sd_desc = {
564         .name = MODULE_NAME,
565         .ctrls = sd_ctrls,
566         .nctrls = ARRAY_SIZE(sd_ctrls),
567         .config = sd_config,
568         .open = sd_open,
569         .start = sd_start,
570         .stopN = sd_stopN,
571         .stop0 = sd_stop0,
572         .close = sd_close,
573         .dq_callback = pac207_do_auto_gain,
574         .pkt_scan = sd_pkt_scan,
575 };
576
577 /* -- module initialisation -- */
578 #define DVNM(name) .driver_info = (kernel_ulong_t) name
579 static const __devinitdata struct usb_device_id device_table[] = {
580         {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
581         {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")},
582         {USB_DEVICE(0x093a, 0x2463), DVNM("Philips spc200nc pac207")},
583         {USB_DEVICE(0x093a, 0x2464), DVNM("Labtec Webcam 1200")},
584         {USB_DEVICE(0x093a, 0x2468), DVNM("PAC207")},
585         {USB_DEVICE(0x093a, 0x2470), DVNM("Genius GF112")},
586         {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")},
587         {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")},
588         {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")},
589         {}
590 };
591 MODULE_DEVICE_TABLE(usb, device_table);
592
593 /* -- device connect -- */
594 static int sd_probe(struct usb_interface *intf,
595                         const struct usb_device_id *id)
596 {
597         return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
598                                 THIS_MODULE);
599 }
600
601 static struct usb_driver sd_driver = {
602         .name = MODULE_NAME,
603         .id_table = device_table,
604         .probe = sd_probe,
605         .disconnect = gspca_disconnect,
606 };
607
608 /* -- module insert / remove -- */
609 static int __init sd_mod_init(void)
610 {
611         if (usb_register(&sd_driver) < 0)
612                 return -1;
613         PDEBUG(D_PROBE, "v%s registered", version);
614         return 0;
615 }
616 static void __exit sd_mod_exit(void)
617 {
618         usb_deregister(&sd_driver);
619         PDEBUG(D_PROBE, "deregistered");
620 }
621
622 module_init(sd_mod_init);
623 module_exit(sd_mod_exit);