blob: 0135ba599e81cb8890d23fd857469a5c27e25502 [file] [log] [blame]
Hans de Goedee2997a72008-04-23 08:09:12 -03001/*
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
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030030#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 4)
31static const char version[] = "2.1.4";
Hans de Goedee2997a72008-04-23 08:09:12 -030032
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
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
Hans de Goedee2997a72008-04-23 08:09:12 -030061/* specific webcam descriptor */
62struct sd {
63 struct gspca_dev gspca_dev; /* !! must be the first item */
64
Hans de Goedee2997a72008-04-23 08:09:12 -030065 u8 mode;
66
67 u8 brightness;
68 u8 exposure;
69 u8 autogain;
70 u8 gain;
71
72 u8 sof_read;
Hans de Goedeab8f12c2008-07-04 18:29:32 -030073 u8 header_read;
Hans de Goedee2997a72008-04-23 08:09:12 -030074 u8 autogain_ignore_frames;
75
76 atomic_t avg_lum;
77};
78
79/* V4L2 controls supported by the driver */
80static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
81static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
82static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
83static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
84static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
86static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
88
89static 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
152static struct cam_mode sif_mode[] = {
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300153 {V4L2_PIX_FMT_PAC207, 176, 144, 1},
154 {V4L2_PIX_FMT_PAC207, 352, 288, 0},
Hans de Goedee2997a72008-04-23 08:09:12 -0300155};
156
157static 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 */
166static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
167
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300168static const unsigned char pac207_sof_marker[5] =
169 { 0xff, 0xff, 0x00, 0xff, 0x96 };
Hans de Goedee2997a72008-04-23 08:09:12 -0300170
171int 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
192int 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
208int 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 */
229static int sd_config(struct gspca_dev *gspca_dev,
230 const struct usb_device_id *id)
231{
Jean-Francois Moine4aa0d032008-05-04 06:46:21 -0300232 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300233 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);
Jean-Francois Moine4aa0d032008-05-04 06:46:21 -0300264 sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
265 sd->exposure = PAC207_EXPOSURE_DEFAULT;
266 sd->gain = PAC207_GAIN_DEFAULT;
Hans de Goedee2997a72008-04-23 08:09:12 -0300267
268 return 0;
269}
270
271/* this function is called at open time */
272static int sd_open(struct gspca_dev *gspca_dev)
273{
274 struct sd *sd = (struct sd *) gspca_dev;
275
Hans de Goedee2997a72008-04-23 08:09:12 -0300276 sd->autogain = 1;
Hans de Goedee2997a72008-04-23 08:09:12 -0300277 return 0;
278}
279
280/* -- start the camera -- */
281static 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) */
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300307 if (gspca_dev->width == 176) { /* 176x144 */
Hans de Goedee2997a72008-04-23 08:09:12 -0300308 mode |= 0x01;
309 PDEBUG(D_STREAM, "pac207_start mode 176x144");
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300310 } else { /* 352x288 */
Hans de Goedee2997a72008-04-23 08:09:12 -0300311 PDEBUG(D_STREAM, "pac207_start mode 352x288");
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300312 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300313 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 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300317 msleep(10);
Hans de Goedee2997a72008-04-23 08:09:12 -0300318 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
325static 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
332static void sd_stop0(struct gspca_dev *gspca_dev)
333{
334}
335
336/* this function is called at close time */
337static void sd_close(struct gspca_dev *gspca_dev)
338{
339}
340
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300341static int sd_get_buff_size_op(struct gspca_dev *gspca_dev, int mode)
Hans de Goedee2997a72008-04-23 08:09:12 -0300342{
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300343 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;
Hans de Goedee2997a72008-04-23 08:09:12 -0300350 }
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300351 return -EIO; /* should never happen */
Hans de Goedee2997a72008-04-23 08:09:12 -0300352}
353
354/* auto gain and exposure algorithm based on the knee algorithm described here:
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300355 * <http://ytse.tricolour.net/docs/LowLightOptimization.html> */
Hans de Goedee2997a72008-04-23 08:09:12 -0300356static 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) {
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300381 if (sd->gain > PAC207_GAIN_KNEE)
Hans de Goedee2997a72008-04-23 08:09:12 -0300382 sd->gain--;
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300383 else if (sd->exposure > PAC207_EXPOSURE_KNEE)
Hans de Goedee2997a72008-04-23 08:09:12 -0300384 sd->exposure--;
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300385 else if (sd->gain > PAC207_GAIN_DEFAULT)
Hans de Goedee2997a72008-04-23 08:09:12 -0300386 sd->gain--;
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300387 else if (sd->exposure > PAC207_EXPOSURE_MIN)
Hans de Goedee2997a72008-04-23 08:09:12 -0300388 sd->exposure--;
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300389 else if (sd->gain > PAC207_GAIN_MIN)
Hans de Goedee2997a72008-04-23 08:09:12 -0300390 sd->gain--;
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300391 else
Hans de Goedee2997a72008-04-23 08:09:12 -0300392 break;
393 } else {
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300394 if (sd->gain < PAC207_GAIN_DEFAULT)
Hans de Goedee2997a72008-04-23 08:09:12 -0300395 sd->gain++;
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300396 else if (sd->exposure < PAC207_EXPOSURE_KNEE)
Hans de Goedee2997a72008-04-23 08:09:12 -0300397 sd->exposure++;
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300398 else if (sd->gain < PAC207_GAIN_KNEE)
Hans de Goedee2997a72008-04-23 08:09:12 -0300399 sd->gain++;
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300400 else if (sd->exposure < PAC207_EXPOSURE_MAX)
Hans de Goedee2997a72008-04-23 08:09:12 -0300401 sd->exposure++;
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300402 else if (sd->gain < PAC207_GAIN_MAX)
Hans de Goedee2997a72008-04-23 08:09:12 -0300403 sd->gain++;
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300404 else
Hans de Goedee2997a72008-04-23 08:09:12 -0300405 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
420static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
Jean-Francois Moine50a871f2008-06-30 19:47:33 -0300421 unsigned char *m, int len)
Hans de Goedee2997a72008-04-23 08:09:12 -0300422{
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 }
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300438 } else {
Hans de Goedee2997a72008-04-23 08:09:12 -0300439 sd->sof_read = 0;
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300440 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300441 }
442
443 return NULL;
444}
445
Hans de Goedee2997a72008-04-23 08:09:12 -0300446static void sd_pkt_scan(struct gspca_dev *gspca_dev,
447 struct gspca_frame *frame,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300448 __u8 *data,
Hans de Goedee2997a72008-04-23 08:09:12 -0300449 int len)
450{
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300451 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300452 unsigned char *sof;
Hans de Goedee2997a72008-04-23 08:09:12 -0300453
454 sof = pac207_find_sof(gspca_dev, data, len);
Hans de Goedee2997a72008-04-23 08:09:12 -0300455 if (sof) {
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300456 int n;
457
Hans de Goedee2997a72008-04-23 08:09:12 -0300458 /* finish decoding current frame */
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300459 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;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300467 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
Hans de Goedee2997a72008-04-23 08:09:12 -0300468 len -= sof - data;
469 data = sof;
470 }
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300471 if (sd->header_read < 11) {
472 int needed;
Hans de Goedee2997a72008-04-23 08:09:12 -0300473
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300474 /* 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 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300490
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300491 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Hans de Goedee2997a72008-04-23 08:09:12 -0300492}
493
494static 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
503static 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
512static 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
521static 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
531static 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
539static 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
553static 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
561static 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
575static 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
583static 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
606static 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 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300615static const struct sd_desc sd_desc = {
Hans de Goedee2997a72008-04-23 08:09:12 -0300616 .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,
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300627 .get_buff_size = sd_get_buff_size_op,
Hans de Goedee2997a72008-04-23 08:09:12 -0300628};
629
630/* -- module initialisation -- */
631#define DVNM(name) .driver_info = (kernel_ulong_t) name
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300632static const __devinitdata struct usb_device_id device_table[] = {
Hans de Goedee2997a72008-04-23 08:09:12 -0300633 {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300634 {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")},
Hans de Goedee2997a72008-04-23 08:09:12 -0300635 {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")},
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300639 {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")},
640 {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")},
Hans de Goedee2997a72008-04-23 08:09:12 -0300641 {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")},
642 {}
643};
644MODULE_DEVICE_TABLE(usb, device_table);
645
646/* -- device connect -- */
647static int sd_probe(struct usb_interface *intf,
648 const struct usb_device_id *id)
649{
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300650 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
651 THIS_MODULE);
Hans de Goedee2997a72008-04-23 08:09:12 -0300652}
653
654static 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 -- */
662static int __init sd_mod_init(void)
663{
Hans de Goedee2997a72008-04-23 08:09:12 -0300664 if (usb_register(&sd_driver) < 0)
665 return -1;
666 PDEBUG(D_PROBE, "v%s registered", version);
667 return 0;
668}
669static void __exit sd_mod_exit(void)
670{
671 usb_deregister(&sd_driver);
672 PDEBUG(D_PROBE, "deregistered");
673}
674
675module_init(sd_mod_init);
676module_exit(sd_mod_exit);