V4L/DVB (8350): gspca: Conform to v4l2 spec and mutex unlock fix.
[linux-2.6-block.git] / drivers / media / video / gspca / pac207.c
CommitLineData
e2997a72
HG
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
c2446b3e
JFM
30#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
31static const char version[] = "2.1.5";
e2997a72
HG
32
33MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
34MODULE_DESCRIPTION("Pixart PAC207");
35MODULE_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
46ccdafa
HG
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
e2997a72 52#define PAC207_EXPOSURE_MAX 26
46ccdafa 53#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 ?? */
e2997a72
HG
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
e2997a72
HG
69/* specific webcam descriptor */
70struct sd {
71 struct gspca_dev gspca_dev; /* !! must be the first item */
72
e2997a72
HG
73 u8 mode;
74
75 u8 brightness;
76 u8 exposure;
77 u8 autogain;
78 u8 gain;
79
80 u8 sof_read;
ab8f12cf 81 u8 header_read;
e2997a72
HG
82 u8 autogain_ignore_frames;
83
84 atomic_t avg_lum;
85};
86
87/* V4L2 controls supported by the driver */
88static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
89static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
90static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
91static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
92static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
93static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
94static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
95static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
96
97static 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
c2446b3e
JFM
160static 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,
80544d3c
HG
169 /* compressed, but only when needed (not compressed
170 when the framerate is low) */
171 .sizeimage = (352 + 2) * 288,
c2446b3e
JFM
172 .colorspace = V4L2_COLORSPACE_SRGB,
173 .priv = 0},
e2997a72
HG
174};
175
176static 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 */
185static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
186
d43fa32f
JFM
187static const unsigned char pac207_sof_marker[5] =
188 { 0xff, 0xff, 0x00, 0xff, 0x96 };
e2997a72
HG
189
190int 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
211int 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
227int 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 */
248static int sd_config(struct gspca_dev *gspca_dev,
249 const struct usb_device_id *id)
250{
4aa0d037 251 struct sd *sd = (struct sd *) gspca_dev;
e2997a72
HG
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);
4aa0d037
JFM
283 sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
284 sd->exposure = PAC207_EXPOSURE_DEFAULT;
285 sd->gain = PAC207_GAIN_DEFAULT;
e2997a72
HG
286
287 return 0;
288}
289
290/* this function is called at open time */
291static int sd_open(struct gspca_dev *gspca_dev)
292{
293 struct sd *sd = (struct sd *) gspca_dev;
294
e2997a72 295 sd->autogain = 1;
e2997a72
HG
296 return 0;
297}
298
299/* -- start the camera -- */
300static 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) */
d43fa32f 326 if (gspca_dev->width == 176) { /* 176x144 */
e2997a72
HG
327 mode |= 0x01;
328 PDEBUG(D_STREAM, "pac207_start mode 176x144");
d43fa32f 329 } else { /* 352x288 */
e2997a72 330 PDEBUG(D_STREAM, "pac207_start mode 352x288");
d43fa32f 331 }
e2997a72
HG
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 */
6a7eba24 336 msleep(10);
e2997a72
HG
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
344static 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
351static void sd_stop0(struct gspca_dev *gspca_dev)
352{
353}
354
355/* this function is called at close time */
356static void sd_close(struct gspca_dev *gspca_dev)
357{
358}
359
e2997a72
HG
360static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
361{
362 struct sd *sd = (struct sd *) gspca_dev;
e2997a72
HG
363 int avg_lum = atomic_read(&sd->avg_lum);
364
dcef3237 365 if (avg_lum == -1)
e2997a72
HG
366 return;
367
dcef3237 368 if (sd->autogain_ignore_frames > 0)
e2997a72 369 sd->autogain_ignore_frames--;
dcef3237
HG
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))
e2997a72 373 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
e2997a72
HG
374}
375
376static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
50a871fe 377 unsigned char *m, int len)
e2997a72
HG
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 }
d43fa32f 394 } else {
e2997a72 395 sd->sof_read = 0;
d43fa32f 396 }
e2997a72
HG
397 }
398
399 return NULL;
400}
401
e2997a72
HG
402static void sd_pkt_scan(struct gspca_dev *gspca_dev,
403 struct gspca_frame *frame,
a5ae2062 404 __u8 *data,
e2997a72
HG
405 int len)
406{
ab8f12cf 407 struct sd *sd = (struct sd *) gspca_dev;
e2997a72 408 unsigned char *sof;
e2997a72
HG
409
410 sof = pac207_find_sof(gspca_dev, data, len);
e2997a72 411 if (sof) {
ab8f12cf
HG
412 int n;
413
e2997a72 414 /* finish decoding current frame */
ab8f12cf
HG
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;
6a7eba24 423 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
e2997a72
HG
424 len -= sof - data;
425 data = sof;
426 }
ab8f12cf
HG
427 if (sd->header_read < 11) {
428 int needed;
e2997a72 429
ab8f12cf
HG
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 }
e2997a72 446
ab8f12cf 447 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
e2997a72
HG
448}
449
450static 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
459static 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
468static 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
477static 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
487static 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
495static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
496{
497 struct sd *sd = (struct sd *) gspca_dev;
498
e2997a72
HG
499 sd->exposure = val;
500 if (gspca_dev->streaming)
501 setexposure(gspca_dev);
502 return 0;
503}
504
505static 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
513static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
514{
515 struct sd *sd = (struct sd *) gspca_dev;
516
e2997a72
HG
517 sd->gain = val;
518 if (gspca_dev->streaming)
519 setgain(gspca_dev);
520 return 0;
521}
522
523static 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
531static 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
554static 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 */
a5ae2062 563static const struct sd_desc sd_desc = {
e2997a72
HG
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
a5ae2062 579static const __devinitdata struct usb_device_id device_table[] = {
e2997a72 580 {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
d43fa32f 581 {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")},
e2997a72
HG
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")},
d43fa32f
JFM
586 {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")},
587 {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")},
e2997a72
HG
588 {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")},
589 {}
590};
591MODULE_DEVICE_TABLE(usb, device_table);
592
593/* -- device connect -- */
594static int sd_probe(struct usb_interface *intf,
595 const struct usb_device_id *id)
596{
d43fa32f
JFM
597 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
598 THIS_MODULE);
e2997a72
HG
599}
600
601static 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 -- */
609static int __init sd_mod_init(void)
610{
e2997a72
HG
611 if (usb_register(&sd_driver) < 0)
612 return -1;
613 PDEBUG(D_PROBE, "v%s registered", version);
614 return 0;
615}
616static void __exit sd_mod_exit(void)
617{
618 usb_deregister(&sd_driver);
619 PDEBUG(D_PROBE, "deregistered");
620}
621
622module_init(sd_mod_init);
623module_exit(sd_mod_exit);