]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/media/video/gspca/pac207.c
V4L/DVB (8438): gspca: Lack of matrix for zc3xx - tas5130c (vf0250).
[mirror_ubuntu-artful-kernel.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
739570bb
JFM
30#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
31static const char version[] = "2.1.7";
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 189
739570bb 190static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
e2997a72
HG
191 const u8 *buffer, u16 length)
192{
193 struct usb_device *udev = gspca_dev->dev;
194 int err;
e2997a72 195
739570bb 196 memcpy(gspca_dev->usb_buf, buffer, length);
e2997a72
HG
197
198 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
199 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
739570bb
JFM
200 0x00, index,
201 gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
e2997a72
HG
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;
e2997a72
HG
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,
739570bb
JFM
234 0x00, index,
235 gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
e2997a72
HG
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
739570bb 243 return gspca_dev->usb_buf[0];
e2997a72
HG
244}
245
e2997a72
HG
246/* this function is called at probe time */
247static int sd_config(struct gspca_dev *gspca_dev,
248 const struct usb_device_id *id)
249{
4aa0d037 250 struct sd *sd = (struct sd *) gspca_dev;
e2997a72
HG
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);
4aa0d037
JFM
282 sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
283 sd->exposure = PAC207_EXPOSURE_DEFAULT;
284 sd->gain = PAC207_GAIN_DEFAULT;
e2997a72
HG
285
286 return 0;
287}
288
289/* this function is called at open time */
290static int sd_open(struct gspca_dev *gspca_dev)
291{
292 struct sd *sd = (struct sd *) gspca_dev;
293
e2997a72 294 sd->autogain = 1;
e2997a72
HG
295 return 0;
296}
297
298/* -- start the camera -- */
299static 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) */
d43fa32f 325 if (gspca_dev->width == 176) { /* 176x144 */
e2997a72
HG
326 mode |= 0x01;
327 PDEBUG(D_STREAM, "pac207_start mode 176x144");
d43fa32f 328 } else { /* 352x288 */
e2997a72 329 PDEBUG(D_STREAM, "pac207_start mode 352x288");
d43fa32f 330 }
e2997a72
HG
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 */
6a7eba24 335 msleep(10);
e2997a72
HG
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
343static 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
350static void sd_stop0(struct gspca_dev *gspca_dev)
351{
352}
353
354/* this function is called at close time */
355static void sd_close(struct gspca_dev *gspca_dev)
356{
357}
358
e2997a72
HG
359static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
360{
361 struct sd *sd = (struct sd *) gspca_dev;
e2997a72
HG
362 int avg_lum = atomic_read(&sd->avg_lum);
363
dcef3237 364 if (avg_lum == -1)
e2997a72
HG
365 return;
366
dcef3237 367 if (sd->autogain_ignore_frames > 0)
e2997a72 368 sd->autogain_ignore_frames--;
dcef3237
HG
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))
e2997a72 372 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
e2997a72
HG
373}
374
375static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
50a871fe 376 unsigned char *m, int len)
e2997a72
HG
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 }
d43fa32f 393 } else {
e2997a72 394 sd->sof_read = 0;
d43fa32f 395 }
e2997a72
HG
396 }
397
398 return NULL;
399}
400
e2997a72
HG
401static void sd_pkt_scan(struct gspca_dev *gspca_dev,
402 struct gspca_frame *frame,
a5ae2062 403 __u8 *data,
e2997a72
HG
404 int len)
405{
ab8f12cf 406 struct sd *sd = (struct sd *) gspca_dev;
e2997a72 407 unsigned char *sof;
e2997a72
HG
408
409 sof = pac207_find_sof(gspca_dev, data, len);
e2997a72 410 if (sof) {
ab8f12cf
HG
411 int n;
412
e2997a72 413 /* finish decoding current frame */
ab8f12cf
HG
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;
6a7eba24 422 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
e2997a72
HG
423 len -= sof - data;
424 data = sof;
425 }
ab8f12cf
HG
426 if (sd->header_read < 11) {
427 int needed;
e2997a72 428
ab8f12cf
HG
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 }
e2997a72 445
ab8f12cf 446 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
e2997a72
HG
447}
448
449static 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
458static 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
467static 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
476static 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
486static 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
494static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
495{
496 struct sd *sd = (struct sd *) gspca_dev;
497
e2997a72
HG
498 sd->exposure = val;
499 if (gspca_dev->streaming)
500 setexposure(gspca_dev);
501 return 0;
502}
503
504static 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
512static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
513{
514 struct sd *sd = (struct sd *) gspca_dev;
515
e2997a72
HG
516 sd->gain = val;
517 if (gspca_dev->streaming)
518 setgain(gspca_dev);
519 return 0;
520}
521
522static 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
530static 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
553static 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 */
a5ae2062 562static const struct sd_desc sd_desc = {
e2997a72
HG
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
a5ae2062 578static const __devinitdata struct usb_device_id device_table[] = {
e2997a72 579 {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
d43fa32f 580 {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")},
e2997a72
HG
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")},
d43fa32f
JFM
585 {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")},
586 {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")},
e2997a72
HG
587 {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")},
588 {}
589};
590MODULE_DEVICE_TABLE(usb, device_table);
591
592/* -- device connect -- */
593static int sd_probe(struct usb_interface *intf,
594 const struct usb_device_id *id)
595{
d43fa32f
JFM
596 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
597 THIS_MODULE);
e2997a72
HG
598}
599
600static 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 -- */
608static int __init sd_mod_init(void)
609{
e2997a72
HG
610 if (usb_register(&sd_driver) < 0)
611 return -1;
612 PDEBUG(D_PROBE, "v%s registered", version);
613 return 0;
614}
615static void __exit sd_mod_exit(void)
616{
617 usb_deregister(&sd_driver);
618 PDEBUG(D_PROBE, "deregistered");
619}
620
621module_init(sd_mod_init);
622module_exit(sd_mod_exit);