blob: d9668f4cb4d177c60b9d17970624cb195d19feb4 [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
Hans de Goedee2997a72008-04-23 08:09:12 -030030MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
31MODULE_DESCRIPTION("Pixart PAC207");
32MODULE_LICENSE("GPL");
33
34#define PAC207_CTRL_TIMEOUT 100 /* ms */
35
36#define PAC207_BRIGHTNESS_MIN 0
37#define PAC207_BRIGHTNESS_MAX 255
38#define PAC207_BRIGHTNESS_DEFAULT 4 /* power on default: 4 */
39
Hans de Goede46ccdaf2008-07-04 18:39:08 -030040/* An exposure value of 4 also works (3 does not) but then we need to lower
41 the compression balance setting when in 352x288 mode, otherwise the usb
42 bandwidth is not enough and packets get dropped resulting in corrupt
43 frames. The problem with this is that when the compression balance gets
44 lowered below 0x80, the pac207 starts using a different compression
45 algorithm for some lines, these lines get prefixed with a 0x2dd2 prefix
46 and currently we do not know how to decompress these lines, so for now
47 we use a minimum exposure value of 5 */
48#define PAC207_EXPOSURE_MIN 5
Hans de Goedee2997a72008-04-23 08:09:12 -030049#define PAC207_EXPOSURE_MAX 26
Hans de Goede46ccdaf2008-07-04 18:39:08 -030050#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 ?? */
Hans de Goedee2997a72008-04-23 08:09:12 -030051#define PAC207_EXPOSURE_KNEE 11 /* 4 = 30 fps, 11 = 8, 15 = 6 */
52
53#define PAC207_GAIN_MIN 0
54#define PAC207_GAIN_MAX 31
55#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */
56#define PAC207_GAIN_KNEE 20
57
58#define PAC207_AUTOGAIN_DEADZONE 30
59/* We calculating the autogain at the end of the transfer of a frame, at this
60 moment a frame with the old settings is being transmitted, and a frame is
61 being captured with the old settings. So if we adjust the autogain we must
62 ignore atleast the 2 next frames for the new settings to come into effect
63 before doing any other adjustments */
64#define PAC207_AUTOGAIN_IGNORE_FRAMES 3
65
Hans de Goedee2997a72008-04-23 08:09:12 -030066/* specific webcam descriptor */
67struct sd {
68 struct gspca_dev gspca_dev; /* !! must be the first item */
69
Hans de Goedee2997a72008-04-23 08:09:12 -030070 u8 mode;
71
72 u8 brightness;
73 u8 exposure;
74 u8 autogain;
75 u8 gain;
76
77 u8 sof_read;
Hans de Goedeab8f12c2008-07-04 18:29:32 -030078 u8 header_read;
Hans de Goedee2997a72008-04-23 08:09:12 -030079 u8 autogain_ignore_frames;
80
81 atomic_t avg_lum;
82};
83
84/* V4L2 controls supported by the driver */
85static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
86static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
87static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
88static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
89static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
90static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
91static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
92static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
93
94static struct ctrl sd_ctrls[] = {
95#define SD_BRIGHTNESS 0
96 {
97 {
98 .id = V4L2_CID_BRIGHTNESS,
99 .type = V4L2_CTRL_TYPE_INTEGER,
100 .name = "Brightness",
101 .minimum = PAC207_BRIGHTNESS_MIN,
102 .maximum = PAC207_BRIGHTNESS_MAX,
103 .step = 1,
104 .default_value = PAC207_BRIGHTNESS_DEFAULT,
105 .flags = 0,
106 },
107 .set = sd_setbrightness,
108 .get = sd_getbrightness,
109 },
110#define SD_EXPOSURE 1
111 {
112 {
113 .id = V4L2_CID_EXPOSURE,
114 .type = V4L2_CTRL_TYPE_INTEGER,
115 .name = "exposure",
116 .minimum = PAC207_EXPOSURE_MIN,
117 .maximum = PAC207_EXPOSURE_MAX,
118 .step = 1,
119 .default_value = PAC207_EXPOSURE_DEFAULT,
120 .flags = 0,
121 },
122 .set = sd_setexposure,
123 .get = sd_getexposure,
124 },
125#define SD_AUTOGAIN 2
126 {
127 {
128 .id = V4L2_CID_AUTOGAIN,
129 .type = V4L2_CTRL_TYPE_BOOLEAN,
130 .name = "Auto Gain",
131 .minimum = 0,
132 .maximum = 1,
133 .step = 1,
134 .default_value = 1,
135 .flags = 0,
136 },
137 .set = sd_setautogain,
138 .get = sd_getautogain,
139 },
140#define SD_GAIN 3
141 {
142 {
143 .id = V4L2_CID_GAIN,
144 .type = V4L2_CTRL_TYPE_INTEGER,
145 .name = "gain",
146 .minimum = PAC207_GAIN_MIN,
147 .maximum = PAC207_GAIN_MAX,
148 .step = 1,
149 .default_value = PAC207_GAIN_DEFAULT,
150 .flags = 0,
151 },
152 .set = sd_setgain,
153 .get = sd_getgain,
154 },
155};
156
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300157static struct v4l2_pix_format sif_mode[] = {
158 {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
159 .bytesperline = 176,
160 .sizeimage = (176 + 2) * 144,
161 /* uncompressed, add 2 bytes / line for line header */
162 .colorspace = V4L2_COLORSPACE_SRGB,
163 .priv = 1},
164 {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
165 .bytesperline = 352,
Hans de Goede80544d32008-07-06 06:40:55 -0300166 /* compressed, but only when needed (not compressed
167 when the framerate is low) */
168 .sizeimage = (352 + 2) * 288,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300169 .colorspace = V4L2_COLORSPACE_SRGB,
170 .priv = 0},
Hans de Goedee2997a72008-04-23 08:09:12 -0300171};
172
173static const __u8 pac207_sensor_init[][8] = {
174 {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
175 {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
176 {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
177 {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
178 {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
179};
180
181 /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
182static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
183
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300184static const unsigned char pac207_sof_marker[5] =
185 { 0xff, 0xff, 0x00, 0xff, 0x96 };
Hans de Goedee2997a72008-04-23 08:09:12 -0300186
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300187static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
Hans de Goedee2997a72008-04-23 08:09:12 -0300188 const u8 *buffer, u16 length)
189{
190 struct usb_device *udev = gspca_dev->dev;
191 int err;
Hans de Goedee2997a72008-04-23 08:09:12 -0300192
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300193 memcpy(gspca_dev->usb_buf, buffer, length);
Hans de Goedee2997a72008-04-23 08:09:12 -0300194
195 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
196 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300197 0x00, index,
198 gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
Hans de Goedee2997a72008-04-23 08:09:12 -0300199 if (err < 0)
200 PDEBUG(D_ERR,
201 "Failed to write registers to index 0x%04X, error %d)",
202 index, err);
203
204 return err;
205}
206
207
Adrian Bunk903e10a2008-07-22 02:35:05 -0300208static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
Hans de Goedee2997a72008-04-23 08:09:12 -0300209{
210 struct usb_device *udev = gspca_dev->dev;
211 int err;
212
213 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
214 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
215 value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
216 if (err)
217 PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
218 " value 0x%02X, error %d)", index, value, err);
219
220 return err;
221}
222
Adrian Bunk903e10a2008-07-22 02:35:05 -0300223static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
Hans de Goedee2997a72008-04-23 08:09:12 -0300224{
225 struct usb_device *udev = gspca_dev->dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300226 int res;
227
228 res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
229 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300230 0x00, index,
231 gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
Hans de Goedee2997a72008-04-23 08:09:12 -0300232 if (res < 0) {
233 PDEBUG(D_ERR,
234 "Failed to read a register (index 0x%04X, error %d)",
235 index, res);
236 return res;
237 }
238
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300239 return gspca_dev->usb_buf[0];
Hans de Goedee2997a72008-04-23 08:09:12 -0300240}
241
Hans de Goedee2997a72008-04-23 08:09:12 -0300242/* this function is called at probe time */
243static int sd_config(struct gspca_dev *gspca_dev,
244 const struct usb_device_id *id)
245{
Jean-Francois Moine4aa0d032008-05-04 06:46:21 -0300246 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300247 struct cam *cam;
248 u8 idreg[2];
249
250 idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
251 idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
252 idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
253 idreg[1] = idreg[1] & 0x0f;
254 PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
255 idreg[0], idreg[1]);
256
257 if (idreg[0] != 0x27) {
258 PDEBUG(D_PROBE, "Error invalid sensor ID!");
259 return -ENODEV;
260 }
261
262 pac207_write_reg(gspca_dev, 0x41, 0x00);
263 /* Bit_0=Image Format,
264 * Bit_1=LED,
265 * Bit_2=Compression test mode enable */
266 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
267 pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
268
269 PDEBUG(D_PROBE,
270 "Pixart PAC207BCA Image Processor and Control Chip detected"
271 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
272
273 cam = &gspca_dev->cam;
Hans de Goedee2997a72008-04-23 08:09:12 -0300274 cam->epaddr = 0x05;
275 cam->cam_mode = sif_mode;
276 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine4aa0d032008-05-04 06:46:21 -0300277 sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
278 sd->exposure = PAC207_EXPOSURE_DEFAULT;
279 sd->gain = PAC207_GAIN_DEFAULT;
Hans de Goedee2997a72008-04-23 08:09:12 -0300280
281 return 0;
282}
283
284/* this function is called at open time */
285static int sd_open(struct gspca_dev *gspca_dev)
286{
287 struct sd *sd = (struct sd *) gspca_dev;
288
Hans de Goedee2997a72008-04-23 08:09:12 -0300289 sd->autogain = 1;
Hans de Goedee2997a72008-04-23 08:09:12 -0300290 return 0;
291}
292
293/* -- start the camera -- */
294static void sd_start(struct gspca_dev *gspca_dev)
295{
296 struct sd *sd = (struct sd *) gspca_dev;
297 __u8 mode;
298
299 pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
300 pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
301 pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
302 pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
303 pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
304 pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
305 pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
306
307 /* Compression Balance */
308 if (gspca_dev->width == 176)
309 pac207_write_reg(gspca_dev, 0x4a, 0xff);
310 else
311 pac207_write_reg(gspca_dev, 0x4a, 0x88);
312 pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
313 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
314
315 /* PGA global gain (Bit 4-0) */
316 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
317 pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
318
319 mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300320 if (gspca_dev->width == 176) { /* 176x144 */
Hans de Goedee2997a72008-04-23 08:09:12 -0300321 mode |= 0x01;
322 PDEBUG(D_STREAM, "pac207_start mode 176x144");
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300323 } else { /* 352x288 */
Hans de Goedee2997a72008-04-23 08:09:12 -0300324 PDEBUG(D_STREAM, "pac207_start mode 352x288");
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300325 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300326 pac207_write_reg(gspca_dev, 0x41, mode);
327
328 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
329 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300330 msleep(10);
Hans de Goedee2997a72008-04-23 08:09:12 -0300331 pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
332
333 sd->sof_read = 0;
334 sd->autogain_ignore_frames = 0;
335 atomic_set(&sd->avg_lum, -1);
336}
337
338static void sd_stopN(struct gspca_dev *gspca_dev)
339{
340 pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
341 pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
342 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
343}
344
345static void sd_stop0(struct gspca_dev *gspca_dev)
346{
347}
348
349/* this function is called at close time */
350static void sd_close(struct gspca_dev *gspca_dev)
351{
352}
353
Hans de Goedee2997a72008-04-23 08:09:12 -0300354static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
355{
356 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300357 int avg_lum = atomic_read(&sd->avg_lum);
358
Hans de Goededcef3232008-07-10 10:40:53 -0300359 if (avg_lum == -1)
Hans de Goedee2997a72008-04-23 08:09:12 -0300360 return;
361
Hans de Goededcef3232008-07-10 10:40:53 -0300362 if (sd->autogain_ignore_frames > 0)
Hans de Goedee2997a72008-04-23 08:09:12 -0300363 sd->autogain_ignore_frames--;
Hans de Goededcef3232008-07-10 10:40:53 -0300364 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
365 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
366 PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
Hans de Goedee2997a72008-04-23 08:09:12 -0300367 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
Hans de Goedee2997a72008-04-23 08:09:12 -0300368}
369
370static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
Jean-Francois Moine50a871f2008-06-30 19:47:33 -0300371 unsigned char *m, int len)
Hans de Goedee2997a72008-04-23 08:09:12 -0300372{
373 struct sd *sd = (struct sd *) gspca_dev;
374 int i;
375
376 /* Search for the SOF marker (fixed part) in the header */
377 for (i = 0; i < len; i++) {
378 if (m[i] == pac207_sof_marker[sd->sof_read]) {
379 sd->sof_read++;
380 if (sd->sof_read == sizeof(pac207_sof_marker)) {
381 PDEBUG(D_STREAM,
382 "SOF found, bytes to analyze: %u."
383 " Frame starts at byte #%u",
384 len, i + 1);
385 sd->sof_read = 0;
386 return m + i + 1;
387 }
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300388 } else {
Hans de Goedee2997a72008-04-23 08:09:12 -0300389 sd->sof_read = 0;
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300390 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300391 }
392
393 return NULL;
394}
395
Hans de Goedee2997a72008-04-23 08:09:12 -0300396static void sd_pkt_scan(struct gspca_dev *gspca_dev,
397 struct gspca_frame *frame,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300398 __u8 *data,
Hans de Goedee2997a72008-04-23 08:09:12 -0300399 int len)
400{
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300401 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300402 unsigned char *sof;
Hans de Goedee2997a72008-04-23 08:09:12 -0300403
404 sof = pac207_find_sof(gspca_dev, data, len);
Hans de Goedee2997a72008-04-23 08:09:12 -0300405 if (sof) {
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300406 int n;
407
Hans de Goedee2997a72008-04-23 08:09:12 -0300408 /* finish decoding current frame */
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300409 n = sof - data;
410 if (n > sizeof pac207_sof_marker)
411 n -= sizeof pac207_sof_marker;
412 else
413 n = 0;
414 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
415 data, n);
416 sd->header_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300417 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
Hans de Goedee2997a72008-04-23 08:09:12 -0300418 len -= sof - data;
419 data = sof;
420 }
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300421 if (sd->header_read < 11) {
422 int needed;
Hans de Goedee2997a72008-04-23 08:09:12 -0300423
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300424 /* get average lumination from frame header (byte 5) */
425 if (sd->header_read < 5) {
426 needed = 5 - sd->header_read;
427 if (len >= needed)
428 atomic_set(&sd->avg_lum, data[needed - 1]);
429 }
430 /* skip the rest of the header */
431 needed = 11 - sd->header_read;
432 if (len <= needed) {
433 sd->header_read += len;
434 return;
435 }
436 data += needed;
437 len -= needed;
438 sd->header_read = 11;
439 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300440
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300441 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Hans de Goedee2997a72008-04-23 08:09:12 -0300442}
443
444static void setbrightness(struct gspca_dev *gspca_dev)
445{
446 struct sd *sd = (struct sd *) gspca_dev;
447
448 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
449 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
450 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
451}
452
453static void setexposure(struct gspca_dev *gspca_dev)
454{
455 struct sd *sd = (struct sd *) gspca_dev;
456
457 pac207_write_reg(gspca_dev, 0x02, sd->exposure);
458 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
459 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
460}
461
462static void setgain(struct gspca_dev *gspca_dev)
463{
464 struct sd *sd = (struct sd *) gspca_dev;
465
466 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
467 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
468 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
469}
470
471static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
472{
473 struct sd *sd = (struct sd *) gspca_dev;
474
475 sd->brightness = val;
476 if (gspca_dev->streaming)
477 setbrightness(gspca_dev);
478 return 0;
479}
480
481static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
482{
483 struct sd *sd = (struct sd *) gspca_dev;
484
485 *val = sd->brightness;
486 return 0;
487}
488
489static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
490{
491 struct sd *sd = (struct sd *) gspca_dev;
492
Hans de Goedee2997a72008-04-23 08:09:12 -0300493 sd->exposure = val;
494 if (gspca_dev->streaming)
495 setexposure(gspca_dev);
496 return 0;
497}
498
499static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
500{
501 struct sd *sd = (struct sd *) gspca_dev;
502
503 *val = sd->exposure;
504 return 0;
505}
506
507static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
508{
509 struct sd *sd = (struct sd *) gspca_dev;
510
Hans de Goedee2997a72008-04-23 08:09:12 -0300511 sd->gain = val;
512 if (gspca_dev->streaming)
513 setgain(gspca_dev);
514 return 0;
515}
516
517static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
518{
519 struct sd *sd = (struct sd *) gspca_dev;
520
521 *val = sd->gain;
522 return 0;
523}
524
525static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
526{
527 struct sd *sd = (struct sd *) gspca_dev;
528
529 sd->autogain = val;
530 /* when switching to autogain set defaults to make sure
531 we are on a valid point of the autogain gain /
532 exposure knee graph, and give this change time to
533 take effect before doing autogain. */
534 if (sd->autogain) {
535 sd->exposure = PAC207_EXPOSURE_DEFAULT;
536 sd->gain = PAC207_GAIN_DEFAULT;
537 if (gspca_dev->streaming) {
538 sd->autogain_ignore_frames =
539 PAC207_AUTOGAIN_IGNORE_FRAMES;
540 setexposure(gspca_dev);
541 setgain(gspca_dev);
542 }
543 }
544
545 return 0;
546}
547
548static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
549{
550 struct sd *sd = (struct sd *) gspca_dev;
551
552 *val = sd->autogain;
553 return 0;
554}
555
556/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300557static const struct sd_desc sd_desc = {
Hans de Goedee2997a72008-04-23 08:09:12 -0300558 .name = MODULE_NAME,
559 .ctrls = sd_ctrls,
560 .nctrls = ARRAY_SIZE(sd_ctrls),
561 .config = sd_config,
562 .open = sd_open,
563 .start = sd_start,
564 .stopN = sd_stopN,
565 .stop0 = sd_stop0,
566 .close = sd_close,
567 .dq_callback = pac207_do_auto_gain,
568 .pkt_scan = sd_pkt_scan,
569};
570
571/* -- module initialisation -- */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300572static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300573 {USB_DEVICE(0x041e, 0x4028)},
574 {USB_DEVICE(0x093a, 0x2460)},
575 {USB_DEVICE(0x093a, 0x2463)},
576 {USB_DEVICE(0x093a, 0x2464)},
577 {USB_DEVICE(0x093a, 0x2468)},
578 {USB_DEVICE(0x093a, 0x2470)},
579 {USB_DEVICE(0x093a, 0x2471)},
580 {USB_DEVICE(0x093a, 0x2472)},
581 {USB_DEVICE(0x2001, 0xf115)},
Hans de Goedee2997a72008-04-23 08:09:12 -0300582 {}
583};
584MODULE_DEVICE_TABLE(usb, device_table);
585
586/* -- device connect -- */
587static int sd_probe(struct usb_interface *intf,
588 const struct usb_device_id *id)
589{
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300590 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
591 THIS_MODULE);
Hans de Goedee2997a72008-04-23 08:09:12 -0300592}
593
594static struct usb_driver sd_driver = {
595 .name = MODULE_NAME,
596 .id_table = device_table,
597 .probe = sd_probe,
598 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300599#ifdef CONFIG_PM
600 .suspend = gspca_suspend,
601 .resume = gspca_resume,
602#endif
Hans de Goedee2997a72008-04-23 08:09:12 -0300603};
604
605/* -- module insert / remove -- */
606static int __init sd_mod_init(void)
607{
Hans de Goedee2997a72008-04-23 08:09:12 -0300608 if (usb_register(&sd_driver) < 0)
609 return -1;
Adrian Bunk903e10a2008-07-22 02:35:05 -0300610 PDEBUG(D_PROBE, "registered");
Hans de Goedee2997a72008-04-23 08:09:12 -0300611 return 0;
612}
613static void __exit sd_mod_exit(void)
614{
615 usb_deregister(&sd_driver);
616 PDEBUG(D_PROBE, "deregistered");
617}
618
619module_init(sd_mod_init);
620module_exit(sd_mod_exit);