0135ba599e81cb8890d23fd857469a5c27e25502
[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, 4)
31 static const char version[] = "2.1.4";
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 #define PAC207_EXPOSURE_MIN             4
44 #define PAC207_EXPOSURE_MAX             26
45 #define PAC207_EXPOSURE_DEFAULT         4 /* power on default: 3 ?? */
46 #define PAC207_EXPOSURE_KNEE            11 /* 4 = 30 fps, 11 = 8, 15 = 6 */
47
48 #define PAC207_GAIN_MIN                 0
49 #define PAC207_GAIN_MAX                 31
50 #define PAC207_GAIN_DEFAULT             9 /* power on default: 9 */
51 #define PAC207_GAIN_KNEE                20
52
53 #define PAC207_AUTOGAIN_DEADZONE        30
54 /* We calculating the autogain at the end of the transfer of a frame, at this
55    moment a frame with the old settings is being transmitted, and a frame is
56    being captured with the old settings. So if we adjust the autogain we must
57    ignore atleast the 2 next frames for the new settings to come into effect
58    before doing any other adjustments */
59 #define PAC207_AUTOGAIN_IGNORE_FRAMES   3
60
61 /* specific webcam descriptor */
62 struct sd {
63         struct gspca_dev gspca_dev;             /* !! must be the first item */
64
65         u8 mode;
66
67         u8 brightness;
68         u8 exposure;
69         u8 autogain;
70         u8 gain;
71
72         u8 sof_read;
73         u8 header_read;
74         u8 autogain_ignore_frames;
75
76         atomic_t avg_lum;
77 };
78
79 /* V4L2 controls supported by the driver */
80 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
81 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
82 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
83 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
84 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
85 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
86 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
87 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
88
89 static struct ctrl sd_ctrls[] = {
90 #define SD_BRIGHTNESS 0
91         {
92             {
93                 .id      = V4L2_CID_BRIGHTNESS,
94                 .type    = V4L2_CTRL_TYPE_INTEGER,
95                 .name    = "Brightness",
96                 .minimum = PAC207_BRIGHTNESS_MIN,
97                 .maximum = PAC207_BRIGHTNESS_MAX,
98                 .step = 1,
99                 .default_value = PAC207_BRIGHTNESS_DEFAULT,
100                 .flags = 0,
101             },
102             .set = sd_setbrightness,
103             .get = sd_getbrightness,
104         },
105 #define SD_EXPOSURE 1
106         {
107             {
108                 .id = V4L2_CID_EXPOSURE,
109                 .type = V4L2_CTRL_TYPE_INTEGER,
110                 .name = "exposure",
111                 .minimum = PAC207_EXPOSURE_MIN,
112                 .maximum = PAC207_EXPOSURE_MAX,
113                 .step = 1,
114                 .default_value = PAC207_EXPOSURE_DEFAULT,
115                 .flags = 0,
116             },
117             .set = sd_setexposure,
118             .get = sd_getexposure,
119         },
120 #define SD_AUTOGAIN 2
121         {
122             {
123                 .id       = V4L2_CID_AUTOGAIN,
124                 .type   = V4L2_CTRL_TYPE_BOOLEAN,
125                 .name   = "Auto Gain",
126                 .minimum = 0,
127                 .maximum = 1,
128                 .step   = 1,
129                 .default_value = 1,
130                 .flags = 0,
131             },
132             .set = sd_setautogain,
133             .get = sd_getautogain,
134         },
135 #define SD_GAIN 3
136         {
137             {
138                 .id = V4L2_CID_GAIN,
139                 .type = V4L2_CTRL_TYPE_INTEGER,
140                 .name = "gain",
141                 .minimum = PAC207_GAIN_MIN,
142                 .maximum = PAC207_GAIN_MAX,
143                 .step = 1,
144                 .default_value = PAC207_GAIN_DEFAULT,
145                 .flags = 0,
146             },
147             .set = sd_setgain,
148             .get = sd_getgain,
149         },
150 };
151
152 static struct cam_mode sif_mode[] = {
153         {V4L2_PIX_FMT_PAC207, 176, 144, 1},
154         {V4L2_PIX_FMT_PAC207, 352, 288, 0},
155 };
156
157 static const __u8 pac207_sensor_init[][8] = {
158         {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
159         {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
160         {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
161         {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
162         {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
163 };
164
165                         /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
166 static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
167
168 static const unsigned char pac207_sof_marker[5] =
169                 { 0xff, 0xff, 0x00, 0xff, 0x96 };
170
171 int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
172         const u8 *buffer, u16 length)
173 {
174         struct usb_device *udev = gspca_dev->dev;
175         int err;
176         u8 kbuf[8];
177
178         memcpy(kbuf, buffer, length);
179
180         err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
181                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
182                         0x00, index, kbuf, length, PAC207_CTRL_TIMEOUT);
183         if (err < 0)
184                 PDEBUG(D_ERR,
185                         "Failed to write registers to index 0x%04X, error %d)",
186                         index, err);
187
188         return err;
189 }
190
191
192 int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
193 {
194         struct usb_device *udev = gspca_dev->dev;
195         int err;
196
197         err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
198                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
199                         value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
200         if (err)
201                 PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
202                         " value 0x%02X, error %d)", index, value, err);
203
204         return err;
205 }
206
207
208 int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
209 {
210         struct usb_device *udev = gspca_dev->dev;
211         u8 buff;
212         int res;
213
214         res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
215                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
216                         0x00, index, &buff, 1, PAC207_CTRL_TIMEOUT);
217         if (res < 0) {
218                 PDEBUG(D_ERR,
219                         "Failed to read a register (index 0x%04X, error %d)",
220                         index, res);
221                 return res;
222         }
223
224         return buff;
225 }
226
227
228 /* this function is called at probe time */
229 static int sd_config(struct gspca_dev *gspca_dev,
230                         const struct usb_device_id *id)
231 {
232         struct sd *sd = (struct sd *) gspca_dev;
233         struct cam *cam;
234         u8 idreg[2];
235
236         idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
237         idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
238         idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
239         idreg[1] = idreg[1] & 0x0f;
240         PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
241                 idreg[0], idreg[1]);
242
243         if (idreg[0] != 0x27) {
244                 PDEBUG(D_PROBE, "Error invalid sensor ID!");
245                 return -ENODEV;
246         }
247
248         pac207_write_reg(gspca_dev, 0x41, 0x00);
249                                 /* Bit_0=Image Format,
250                                  * Bit_1=LED,
251                                  * Bit_2=Compression test mode enable */
252         pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
253         pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
254
255         PDEBUG(D_PROBE,
256                 "Pixart PAC207BCA Image Processor and Control Chip detected"
257                 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
258
259         cam = &gspca_dev->cam;
260         cam->dev_name = (char *) id->driver_info;
261         cam->epaddr = 0x05;
262         cam->cam_mode = sif_mode;
263         cam->nmodes = ARRAY_SIZE(sif_mode);
264         sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
265         sd->exposure = PAC207_EXPOSURE_DEFAULT;
266         sd->gain = PAC207_GAIN_DEFAULT;
267
268         return 0;
269 }
270
271 /* this function is called at open time */
272 static int sd_open(struct gspca_dev *gspca_dev)
273 {
274         struct sd *sd = (struct sd *) gspca_dev;
275
276         sd->autogain = 1;
277         return 0;
278 }
279
280 /* -- start the camera -- */
281 static void sd_start(struct gspca_dev *gspca_dev)
282 {
283         struct sd *sd = (struct sd *) gspca_dev;
284         __u8 mode;
285
286         pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
287         pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
288         pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
289         pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
290         pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
291         pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
292         pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
293
294         /* Compression Balance */
295         if (gspca_dev->width == 176)
296                 pac207_write_reg(gspca_dev, 0x4a, 0xff);
297         else
298                 pac207_write_reg(gspca_dev, 0x4a, 0x88);
299         pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
300         pac207_write_reg(gspca_dev, 0x08, sd->brightness);
301
302         /* PGA global gain (Bit 4-0) */
303         pac207_write_reg(gspca_dev, 0x0e, sd->gain);
304         pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
305
306         mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
307         if (gspca_dev->width == 176) {  /* 176x144 */
308                 mode |= 0x01;
309                 PDEBUG(D_STREAM, "pac207_start mode 176x144");
310         } else {                                /* 352x288 */
311                 PDEBUG(D_STREAM, "pac207_start mode 352x288");
312         }
313         pac207_write_reg(gspca_dev, 0x41, mode);
314
315         pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
316         pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
317         msleep(10);
318         pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
319
320         sd->sof_read = 0;
321         sd->autogain_ignore_frames = 0;
322         atomic_set(&sd->avg_lum, -1);
323 }
324
325 static void sd_stopN(struct gspca_dev *gspca_dev)
326 {
327         pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
328         pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
329         pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
330 }
331
332 static void sd_stop0(struct gspca_dev *gspca_dev)
333 {
334 }
335
336 /* this function is called at close time */
337 static void sd_close(struct gspca_dev *gspca_dev)
338 {
339 }
340
341 static int sd_get_buff_size_op(struct gspca_dev *gspca_dev, int mode)
342 {
343         switch (gspca_dev->cam.cam_mode[mode].width) {
344         case 176: /* 176x144 */
345                 /* uncompressed, add 2 bytes / line for line header */
346                 return (176 + 2) * 144;
347         case 352: /* 352x288 */
348                 /* compressed */
349                 return 352 * 288 / 2;
350         }
351         return -EIO; /* should never happen */
352 }
353
354 /* auto gain and exposure algorithm based on the knee algorithm described here:
355  * <http://ytse.tricolour.net/docs/LowLightOptimization.html> */
356 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
357 {
358         struct sd *sd = (struct sd *) gspca_dev;
359         int i, steps, desired_avg_lum;
360         int orig_gain = sd->gain;
361         int orig_exposure = sd->exposure;
362         int avg_lum = atomic_read(&sd->avg_lum);
363
364         if (!sd->autogain || avg_lum == -1)
365                 return;
366
367         if (sd->autogain_ignore_frames > 0) {
368                 sd->autogain_ignore_frames--;
369                 return;
370         }
371
372         /* correct desired lumination for the configured brightness */
373         desired_avg_lum = 100 + sd->brightness / 2;
374
375         /* If we are of a multiple of deadzone, do multiple step to reach the
376            desired lumination fast (with the risc of a slight overshoot) */
377         steps = abs(desired_avg_lum - avg_lum) / PAC207_AUTOGAIN_DEADZONE;
378
379         for (i = 0; i < steps; i++) {
380                 if (avg_lum > desired_avg_lum) {
381                         if (sd->gain > PAC207_GAIN_KNEE)
382                                 sd->gain--;
383                         else if (sd->exposure > PAC207_EXPOSURE_KNEE)
384                                 sd->exposure--;
385                         else if (sd->gain > PAC207_GAIN_DEFAULT)
386                                 sd->gain--;
387                         else if (sd->exposure > PAC207_EXPOSURE_MIN)
388                                 sd->exposure--;
389                         else if (sd->gain > PAC207_GAIN_MIN)
390                                 sd->gain--;
391                         else
392                                 break;
393                 } else {
394                         if (sd->gain < PAC207_GAIN_DEFAULT)
395                                 sd->gain++;
396                         else if (sd->exposure < PAC207_EXPOSURE_KNEE)
397                                 sd->exposure++;
398                         else if (sd->gain < PAC207_GAIN_KNEE)
399                                 sd->gain++;
400                         else if (sd->exposure < PAC207_EXPOSURE_MAX)
401                                 sd->exposure++;
402                         else if (sd->gain < PAC207_GAIN_MAX)
403                                 sd->gain++;
404                         else
405                                 break;
406                 }
407         }
408
409         if (sd->exposure != orig_exposure || sd->gain != orig_gain) {
410                 if (sd->exposure != orig_exposure)
411                         pac207_write_reg(gspca_dev, 0x0002, sd->exposure);
412                 if (sd->gain != orig_gain)
413                         pac207_write_reg(gspca_dev, 0x000e, sd->gain);
414                 pac207_write_reg(gspca_dev, 0x13, 0x01); /* load reg to sen */
415                 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
416                 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
417         }
418 }
419
420 static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
421                                         unsigned char *m, int len)
422 {
423         struct sd *sd = (struct sd *) gspca_dev;
424         int i;
425
426         /* Search for the SOF marker (fixed part) in the header */
427         for (i = 0; i < len; i++) {
428                 if (m[i] == pac207_sof_marker[sd->sof_read]) {
429                         sd->sof_read++;
430                         if (sd->sof_read == sizeof(pac207_sof_marker)) {
431                                 PDEBUG(D_STREAM,
432                                         "SOF found, bytes to analyze: %u."
433                                         " Frame starts at byte #%u",
434                                         len, i + 1);
435                                 sd->sof_read = 0;
436                                 return m + i + 1;
437                         }
438                 } else {
439                         sd->sof_read = 0;
440                 }
441         }
442
443         return NULL;
444 }
445
446 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
447                         struct gspca_frame *frame,
448                         __u8 *data,
449                         int len)
450 {
451         struct sd *sd = (struct sd *) gspca_dev;
452         unsigned char *sof;
453
454         sof = pac207_find_sof(gspca_dev, data, len);
455         if (sof) {
456                 int n;
457
458                 /* finish decoding current frame */
459                 n = sof - data;
460                 if (n > sizeof pac207_sof_marker)
461                         n -= sizeof pac207_sof_marker;
462                 else
463                         n = 0;
464                 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
465                                         data, n);
466                 sd->header_read = 0;
467                 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
468                 len -= sof - data;
469                 data = sof;
470         }
471         if (sd->header_read < 11) {
472                 int needed;
473
474                 /* get average lumination from frame header (byte 5) */
475                 if (sd->header_read < 5) {
476                         needed = 5 - sd->header_read;
477                         if (len >= needed)
478                                 atomic_set(&sd->avg_lum, data[needed - 1]);
479                 }
480                 /* skip the rest of the header */
481                 needed = 11 - sd->header_read;
482                 if (len <= needed) {
483                         sd->header_read += len;
484                         return;
485                 }
486                 data += needed;
487                 len -= needed;
488                 sd->header_read = 11;
489         }
490
491         gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
492 }
493
494 static void setbrightness(struct gspca_dev *gspca_dev)
495 {
496         struct sd *sd = (struct sd *) gspca_dev;
497
498         pac207_write_reg(gspca_dev, 0x08, sd->brightness);
499         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
500         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
501 }
502
503 static void setexposure(struct gspca_dev *gspca_dev)
504 {
505         struct sd *sd = (struct sd *) gspca_dev;
506
507         pac207_write_reg(gspca_dev, 0x02, sd->exposure);
508         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
509         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
510 }
511
512 static void setgain(struct gspca_dev *gspca_dev)
513 {
514         struct sd *sd = (struct sd *) gspca_dev;
515
516         pac207_write_reg(gspca_dev, 0x0e, sd->gain);
517         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
518         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
519 }
520
521 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
522 {
523         struct sd *sd = (struct sd *) gspca_dev;
524
525         sd->brightness = val;
526         if (gspca_dev->streaming)
527                 setbrightness(gspca_dev);
528         return 0;
529 }
530
531 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
532 {
533         struct sd *sd = (struct sd *) gspca_dev;
534
535         *val = sd->brightness;
536         return 0;
537 }
538
539 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
540 {
541         struct sd *sd = (struct sd *) gspca_dev;
542
543         /* don't allow mucking with exposure when using autogain */
544         if (sd->autogain)
545                 return -EINVAL;
546
547         sd->exposure = val;
548         if (gspca_dev->streaming)
549                 setexposure(gspca_dev);
550         return 0;
551 }
552
553 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
554 {
555         struct sd *sd = (struct sd *) gspca_dev;
556
557         *val = sd->exposure;
558         return 0;
559 }
560
561 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
562 {
563         struct sd *sd = (struct sd *) gspca_dev;
564
565         /* don't allow mucking with gain when using autogain */
566         if (sd->autogain)
567                 return -EINVAL;
568
569         sd->gain = val;
570         if (gspca_dev->streaming)
571                 setgain(gspca_dev);
572         return 0;
573 }
574
575 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
576 {
577         struct sd *sd = (struct sd *) gspca_dev;
578
579         *val = sd->gain;
580         return 0;
581 }
582
583 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
584 {
585         struct sd *sd = (struct sd *) gspca_dev;
586
587         sd->autogain = val;
588         /* when switching to autogain set defaults to make sure
589            we are on a valid point of the autogain gain /
590            exposure knee graph, and give this change time to
591            take effect before doing autogain. */
592         if (sd->autogain) {
593                 sd->exposure = PAC207_EXPOSURE_DEFAULT;
594                 sd->gain = PAC207_GAIN_DEFAULT;
595                 if (gspca_dev->streaming) {
596                         sd->autogain_ignore_frames =
597                                 PAC207_AUTOGAIN_IGNORE_FRAMES;
598                         setexposure(gspca_dev);
599                         setgain(gspca_dev);
600                 }
601         }
602
603         return 0;
604 }
605
606 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
607 {
608         struct sd *sd = (struct sd *) gspca_dev;
609
610         *val = sd->autogain;
611         return 0;
612 }
613
614 /* sub-driver description */
615 static const struct sd_desc sd_desc = {
616         .name = MODULE_NAME,
617         .ctrls = sd_ctrls,
618         .nctrls = ARRAY_SIZE(sd_ctrls),
619         .config = sd_config,
620         .open = sd_open,
621         .start = sd_start,
622         .stopN = sd_stopN,
623         .stop0 = sd_stop0,
624         .close = sd_close,
625         .dq_callback = pac207_do_auto_gain,
626         .pkt_scan = sd_pkt_scan,
627         .get_buff_size = sd_get_buff_size_op,
628 };
629
630 /* -- module initialisation -- */
631 #define DVNM(name) .driver_info = (kernel_ulong_t) name
632 static const __devinitdata struct usb_device_id device_table[] = {
633         {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
634         {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")},
635         {USB_DEVICE(0x093a, 0x2463), DVNM("Philips spc200nc pac207")},
636         {USB_DEVICE(0x093a, 0x2464), DVNM("Labtec Webcam 1200")},
637         {USB_DEVICE(0x093a, 0x2468), DVNM("PAC207")},
638         {USB_DEVICE(0x093a, 0x2470), DVNM("Genius GF112")},
639         {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")},
640         {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")},
641         {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")},
642         {}
643 };
644 MODULE_DEVICE_TABLE(usb, device_table);
645
646 /* -- device connect -- */
647 static int sd_probe(struct usb_interface *intf,
648                         const struct usb_device_id *id)
649 {
650         return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
651                                 THIS_MODULE);
652 }
653
654 static struct usb_driver sd_driver = {
655         .name = MODULE_NAME,
656         .id_table = device_table,
657         .probe = sd_probe,
658         .disconnect = gspca_disconnect,
659 };
660
661 /* -- module insert / remove -- */
662 static int __init sd_mod_init(void)
663 {
664         if (usb_register(&sd_driver) < 0)
665                 return -1;
666         PDEBUG(D_PROBE, "v%s registered", version);
667         return 0;
668 }
669 static void __exit sd_mod_exit(void)
670 {
671         usb_deregister(&sd_driver);
672         PDEBUG(D_PROBE, "deregistered");
673 }
674
675 module_init(sd_mod_init);
676 module_exit(sd_mod_exit);