blob: fa7abc411090c48e7803be522bda37640c36eea2 [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 Moine739570b2008-07-14 09:38:29 -030030#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
31static const char version[] = "2.1.7";
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
Hans de Goede46ccdaf2008-07-04 18:39:08 -030043/* 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
Hans de Goedee2997a72008-04-23 08:09:12 -030052#define PAC207_EXPOSURE_MAX 26
Hans de Goede46ccdaf2008-07-04 18:39:08 -030053#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 ?? */
Hans de Goedee2997a72008-04-23 08:09:12 -030054#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
Hans de Goedee2997a72008-04-23 08:09:12 -030069/* specific webcam descriptor */
70struct sd {
71 struct gspca_dev gspca_dev; /* !! must be the first item */
72
Hans de Goedee2997a72008-04-23 08:09:12 -030073 u8 mode;
74
75 u8 brightness;
76 u8 exposure;
77 u8 autogain;
78 u8 gain;
79
80 u8 sof_read;
Hans de Goedeab8f12c2008-07-04 18:29:32 -030081 u8 header_read;
Hans de Goedee2997a72008-04-23 08:09:12 -030082 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
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300160static 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,
Hans de Goede80544d32008-07-06 06:40:55 -0300169 /* compressed, but only when needed (not compressed
170 when the framerate is low) */
171 .sizeimage = (352 + 2) * 288,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300172 .colorspace = V4L2_COLORSPACE_SRGB,
173 .priv = 0},
Hans de Goedee2997a72008-04-23 08:09:12 -0300174};
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
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300187static const unsigned char pac207_sof_marker[5] =
188 { 0xff, 0xff, 0x00, 0xff, 0x96 };
Hans de Goedee2997a72008-04-23 08:09:12 -0300189
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300190static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
Hans de Goedee2997a72008-04-23 08:09:12 -0300191 const u8 *buffer, u16 length)
192{
193 struct usb_device *udev = gspca_dev->dev;
194 int err;
Hans de Goedee2997a72008-04-23 08:09:12 -0300195
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300196 memcpy(gspca_dev->usb_buf, buffer, length);
Hans de Goedee2997a72008-04-23 08:09:12 -0300197
198 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
199 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300200 0x00, index,
201 gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
Hans de Goedee2997a72008-04-23 08:09:12 -0300202 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;
Hans de Goedee2997a72008-04-23 08:09:12 -0300230 int res;
231
232 res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
233 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300234 0x00, index,
235 gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
Hans de Goedee2997a72008-04-23 08:09:12 -0300236 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
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300243 return gspca_dev->usb_buf[0];
Hans de Goedee2997a72008-04-23 08:09:12 -0300244}
245
Hans de Goedee2997a72008-04-23 08:09:12 -0300246/* this function is called at probe time */
247static int sd_config(struct gspca_dev *gspca_dev,
248 const struct usb_device_id *id)
249{
Jean-Francois Moine4aa0d032008-05-04 06:46:21 -0300250 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300251 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);
Jean-Francois Moine4aa0d032008-05-04 06:46:21 -0300282 sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
283 sd->exposure = PAC207_EXPOSURE_DEFAULT;
284 sd->gain = PAC207_GAIN_DEFAULT;
Hans de Goedee2997a72008-04-23 08:09:12 -0300285
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
Hans de Goedee2997a72008-04-23 08:09:12 -0300294 sd->autogain = 1;
Hans de Goedee2997a72008-04-23 08:09:12 -0300295 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) */
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300325 if (gspca_dev->width == 176) { /* 176x144 */
Hans de Goedee2997a72008-04-23 08:09:12 -0300326 mode |= 0x01;
327 PDEBUG(D_STREAM, "pac207_start mode 176x144");
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300328 } else { /* 352x288 */
Hans de Goedee2997a72008-04-23 08:09:12 -0300329 PDEBUG(D_STREAM, "pac207_start mode 352x288");
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300330 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300331 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 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300335 msleep(10);
Hans de Goedee2997a72008-04-23 08:09:12 -0300336 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
Hans de Goedee2997a72008-04-23 08:09:12 -0300359static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
360{
361 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300362 int avg_lum = atomic_read(&sd->avg_lum);
363
Hans de Goededcef3232008-07-10 10:40:53 -0300364 if (avg_lum == -1)
Hans de Goedee2997a72008-04-23 08:09:12 -0300365 return;
366
Hans de Goededcef3232008-07-10 10:40:53 -0300367 if (sd->autogain_ignore_frames > 0)
Hans de Goedee2997a72008-04-23 08:09:12 -0300368 sd->autogain_ignore_frames--;
Hans de Goededcef3232008-07-10 10:40:53 -0300369 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))
Hans de Goedee2997a72008-04-23 08:09:12 -0300372 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
Hans de Goedee2997a72008-04-23 08:09:12 -0300373}
374
375static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
Jean-Francois Moine50a871f2008-06-30 19:47:33 -0300376 unsigned char *m, int len)
Hans de Goedee2997a72008-04-23 08:09:12 -0300377{
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 }
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300393 } else {
Hans de Goedee2997a72008-04-23 08:09:12 -0300394 sd->sof_read = 0;
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300395 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300396 }
397
398 return NULL;
399}
400
Hans de Goedee2997a72008-04-23 08:09:12 -0300401static void sd_pkt_scan(struct gspca_dev *gspca_dev,
402 struct gspca_frame *frame,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300403 __u8 *data,
Hans de Goedee2997a72008-04-23 08:09:12 -0300404 int len)
405{
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300406 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300407 unsigned char *sof;
Hans de Goedee2997a72008-04-23 08:09:12 -0300408
409 sof = pac207_find_sof(gspca_dev, data, len);
Hans de Goedee2997a72008-04-23 08:09:12 -0300410 if (sof) {
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300411 int n;
412
Hans de Goedee2997a72008-04-23 08:09:12 -0300413 /* finish decoding current frame */
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300414 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;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300422 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
Hans de Goedee2997a72008-04-23 08:09:12 -0300423 len -= sof - data;
424 data = sof;
425 }
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300426 if (sd->header_read < 11) {
427 int needed;
Hans de Goedee2997a72008-04-23 08:09:12 -0300428
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300429 /* 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 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300445
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300446 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Hans de Goedee2997a72008-04-23 08:09:12 -0300447}
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
Hans de Goedee2997a72008-04-23 08:09:12 -0300498 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
Hans de Goedee2997a72008-04-23 08:09:12 -0300516 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 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300562static const struct sd_desc sd_desc = {
Hans de Goedee2997a72008-04-23 08:09:12 -0300563 .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
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300578static const __devinitdata struct usb_device_id device_table[] = {
Hans de Goedee2997a72008-04-23 08:09:12 -0300579 {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300580 {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")},
Hans de Goedee2997a72008-04-23 08:09:12 -0300581 {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")},
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300585 {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")},
586 {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")},
Hans de Goedee2997a72008-04-23 08:09:12 -0300587 {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{
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300596 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
597 THIS_MODULE);
Hans de Goedee2997a72008-04-23 08:09:12 -0300598}
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{
Hans de Goedee2997a72008-04-23 08:09:12 -0300610 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);