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