blob: e6b5c8a5b5d9426271b636e46c78104f30908390 [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,
Jean-Francois Moine66e41242008-09-03 17:12:16 -0300134#define AUTOGAIN_DEF 1
135 .default_value = AUTOGAIN_DEF,
Hans de Goedee2997a72008-04-23 08:09:12 -0300136 .flags = 0,
137 },
138 .set = sd_setautogain,
139 .get = sd_getautogain,
140 },
141#define SD_GAIN 3
142 {
143 {
144 .id = V4L2_CID_GAIN,
145 .type = V4L2_CTRL_TYPE_INTEGER,
146 .name = "gain",
147 .minimum = PAC207_GAIN_MIN,
148 .maximum = PAC207_GAIN_MAX,
149 .step = 1,
150 .default_value = PAC207_GAIN_DEFAULT,
151 .flags = 0,
152 },
153 .set = sd_setgain,
154 .get = sd_getgain,
155 },
156};
157
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300158static struct v4l2_pix_format sif_mode[] = {
159 {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
160 .bytesperline = 176,
161 .sizeimage = (176 + 2) * 144,
162 /* uncompressed, add 2 bytes / line for line header */
163 .colorspace = V4L2_COLORSPACE_SRGB,
164 .priv = 1},
165 {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
166 .bytesperline = 352,
Hans de Goede80544d32008-07-06 06:40:55 -0300167 /* compressed, but only when needed (not compressed
168 when the framerate is low) */
169 .sizeimage = (352 + 2) * 288,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300170 .colorspace = V4L2_COLORSPACE_SRGB,
171 .priv = 0},
Hans de Goedee2997a72008-04-23 08:09:12 -0300172};
173
174static const __u8 pac207_sensor_init[][8] = {
175 {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
176 {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
177 {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
178 {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
179 {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
180};
181
182 /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
183static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
184
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300185static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
Hans de Goedee2997a72008-04-23 08:09:12 -0300186 const u8 *buffer, u16 length)
187{
188 struct usb_device *udev = gspca_dev->dev;
189 int err;
Hans de Goedee2997a72008-04-23 08:09:12 -0300190
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300191 memcpy(gspca_dev->usb_buf, buffer, length);
Hans de Goedee2997a72008-04-23 08:09:12 -0300192
193 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
194 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300195 0x00, index,
196 gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
Hans de Goedee2997a72008-04-23 08:09:12 -0300197 if (err < 0)
198 PDEBUG(D_ERR,
199 "Failed to write registers to index 0x%04X, error %d)",
200 index, err);
201
202 return err;
203}
204
205
Adrian Bunk903e10a2008-07-22 02:35:05 -0300206static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
Hans de Goedee2997a72008-04-23 08:09:12 -0300207{
208 struct usb_device *udev = gspca_dev->dev;
209 int err;
210
211 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
212 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
213 value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
214 if (err)
215 PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
216 " value 0x%02X, error %d)", index, value, err);
217
218 return err;
219}
220
Adrian Bunk903e10a2008-07-22 02:35:05 -0300221static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
Hans de Goedee2997a72008-04-23 08:09:12 -0300222{
223 struct usb_device *udev = gspca_dev->dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300224 int res;
225
226 res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
227 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300228 0x00, index,
229 gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
Hans de Goedee2997a72008-04-23 08:09:12 -0300230 if (res < 0) {
231 PDEBUG(D_ERR,
232 "Failed to read a register (index 0x%04X, error %d)",
233 index, res);
234 return res;
235 }
236
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300237 return gspca_dev->usb_buf[0];
Hans de Goedee2997a72008-04-23 08:09:12 -0300238}
239
Hans de Goedee2997a72008-04-23 08:09:12 -0300240/* this function is called at probe time */
241static int sd_config(struct gspca_dev *gspca_dev,
242 const struct usb_device_id *id)
243{
Jean-Francois Moine4aa0d032008-05-04 06:46:21 -0300244 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300245 struct cam *cam;
246 u8 idreg[2];
247
248 idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
249 idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
250 idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
251 idreg[1] = idreg[1] & 0x0f;
252 PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
253 idreg[0], idreg[1]);
254
255 if (idreg[0] != 0x27) {
256 PDEBUG(D_PROBE, "Error invalid sensor ID!");
257 return -ENODEV;
258 }
259
Hans de Goedee2997a72008-04-23 08:09:12 -0300260 PDEBUG(D_PROBE,
261 "Pixart PAC207BCA Image Processor and Control Chip detected"
262 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
263
264 cam = &gspca_dev->cam;
Hans de Goedee2997a72008-04-23 08:09:12 -0300265 cam->epaddr = 0x05;
266 cam->cam_mode = sif_mode;
267 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine4aa0d032008-05-04 06:46:21 -0300268 sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
269 sd->exposure = PAC207_EXPOSURE_DEFAULT;
270 sd->gain = PAC207_GAIN_DEFAULT;
Jean-Francois Moine66e41242008-09-03 17:12:16 -0300271 sd->autogain = AUTOGAIN_DEF;
Hans de Goedee2997a72008-04-23 08:09:12 -0300272
273 return 0;
274}
275
276/* this function is called at open time */
277static int sd_open(struct gspca_dev *gspca_dev)
278{
Jean-Francois Moine66e41242008-09-03 17:12:16 -0300279 pac207_write_reg(gspca_dev, 0x41, 0x00);
280 /* Bit_0=Image Format,
281 * Bit_1=LED,
282 * Bit_2=Compression test mode enable */
283 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
284 pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
Hans de Goedee2997a72008-04-23 08:09:12 -0300285
Hans de Goedee2997a72008-04-23 08:09:12 -0300286 return 0;
287}
288
289/* -- start the camera -- */
290static void sd_start(struct gspca_dev *gspca_dev)
291{
292 struct sd *sd = (struct sd *) gspca_dev;
293 __u8 mode;
294
295 pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
296 pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
297 pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
298 pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
299 pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
300 pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
301 pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
302
303 /* Compression Balance */
304 if (gspca_dev->width == 176)
305 pac207_write_reg(gspca_dev, 0x4a, 0xff);
306 else
307 pac207_write_reg(gspca_dev, 0x4a, 0x88);
308 pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
309 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
310
311 /* PGA global gain (Bit 4-0) */
312 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
313 pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
314
315 mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300316 if (gspca_dev->width == 176) { /* 176x144 */
Hans de Goedee2997a72008-04-23 08:09:12 -0300317 mode |= 0x01;
318 PDEBUG(D_STREAM, "pac207_start mode 176x144");
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300319 } else { /* 352x288 */
Hans de Goedee2997a72008-04-23 08:09:12 -0300320 PDEBUG(D_STREAM, "pac207_start mode 352x288");
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300321 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300322 pac207_write_reg(gspca_dev, 0x41, mode);
323
324 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
325 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300326 msleep(10);
Hans de Goedee2997a72008-04-23 08:09:12 -0300327 pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
328
329 sd->sof_read = 0;
330 sd->autogain_ignore_frames = 0;
331 atomic_set(&sd->avg_lum, -1);
332}
333
334static void sd_stopN(struct gspca_dev *gspca_dev)
335{
336 pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
337 pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
338 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
339}
340
341static void sd_stop0(struct gspca_dev *gspca_dev)
342{
343}
344
345/* this function is called at close time */
346static void sd_close(struct gspca_dev *gspca_dev)
347{
348}
349
Hans de Goedee2997a72008-04-23 08:09:12 -0300350static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
351{
352 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300353 int avg_lum = atomic_read(&sd->avg_lum);
354
Hans de Goededcef3232008-07-10 10:40:53 -0300355 if (avg_lum == -1)
Hans de Goedee2997a72008-04-23 08:09:12 -0300356 return;
357
Hans de Goededcef3232008-07-10 10:40:53 -0300358 if (sd->autogain_ignore_frames > 0)
Hans de Goedee2997a72008-04-23 08:09:12 -0300359 sd->autogain_ignore_frames--;
Hans de Goededcef3232008-07-10 10:40:53 -0300360 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
361 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
362 PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
Hans de Goedee2997a72008-04-23 08:09:12 -0300363 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
Hans de Goedee2997a72008-04-23 08:09:12 -0300364}
365
Hans de Goede327c4ab2008-09-03 17:12:14 -0300366/* Include pac common sof detection functions */
367#include "pac_common.h"
Hans de Goedee2997a72008-04-23 08:09:12 -0300368
Hans de Goedee2997a72008-04-23 08:09:12 -0300369static void sd_pkt_scan(struct gspca_dev *gspca_dev,
370 struct gspca_frame *frame,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300371 __u8 *data,
Hans de Goedee2997a72008-04-23 08:09:12 -0300372 int len)
373{
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300374 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300375 unsigned char *sof;
Hans de Goedee2997a72008-04-23 08:09:12 -0300376
Hans de Goede327c4ab2008-09-03 17:12:14 -0300377 sof = pac_find_sof(gspca_dev, data, len);
Hans de Goedee2997a72008-04-23 08:09:12 -0300378 if (sof) {
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300379 int n;
380
Hans de Goedee2997a72008-04-23 08:09:12 -0300381 /* finish decoding current frame */
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300382 n = sof - data;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300383 if (n > sizeof pac_sof_marker)
384 n -= sizeof pac_sof_marker;
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300385 else
386 n = 0;
387 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
388 data, n);
389 sd->header_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300390 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
Hans de Goedee2997a72008-04-23 08:09:12 -0300391 len -= sof - data;
392 data = sof;
393 }
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300394 if (sd->header_read < 11) {
395 int needed;
Hans de Goedee2997a72008-04-23 08:09:12 -0300396
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300397 /* get average lumination from frame header (byte 5) */
398 if (sd->header_read < 5) {
399 needed = 5 - sd->header_read;
400 if (len >= needed)
401 atomic_set(&sd->avg_lum, data[needed - 1]);
402 }
403 /* skip the rest of the header */
404 needed = 11 - sd->header_read;
405 if (len <= needed) {
406 sd->header_read += len;
407 return;
408 }
409 data += needed;
410 len -= needed;
411 sd->header_read = 11;
412 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300413
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300414 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Hans de Goedee2997a72008-04-23 08:09:12 -0300415}
416
417static void setbrightness(struct gspca_dev *gspca_dev)
418{
419 struct sd *sd = (struct sd *) gspca_dev;
420
421 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
422 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
423 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
424}
425
426static void setexposure(struct gspca_dev *gspca_dev)
427{
428 struct sd *sd = (struct sd *) gspca_dev;
429
430 pac207_write_reg(gspca_dev, 0x02, sd->exposure);
431 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
432 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
433}
434
435static void setgain(struct gspca_dev *gspca_dev)
436{
437 struct sd *sd = (struct sd *) gspca_dev;
438
439 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
440 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
441 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
442}
443
444static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
445{
446 struct sd *sd = (struct sd *) gspca_dev;
447
448 sd->brightness = val;
449 if (gspca_dev->streaming)
450 setbrightness(gspca_dev);
451 return 0;
452}
453
454static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
455{
456 struct sd *sd = (struct sd *) gspca_dev;
457
458 *val = sd->brightness;
459 return 0;
460}
461
462static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
463{
464 struct sd *sd = (struct sd *) gspca_dev;
465
Hans de Goedee2997a72008-04-23 08:09:12 -0300466 sd->exposure = val;
467 if (gspca_dev->streaming)
468 setexposure(gspca_dev);
469 return 0;
470}
471
472static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
473{
474 struct sd *sd = (struct sd *) gspca_dev;
475
476 *val = sd->exposure;
477 return 0;
478}
479
480static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
481{
482 struct sd *sd = (struct sd *) gspca_dev;
483
Hans de Goedee2997a72008-04-23 08:09:12 -0300484 sd->gain = val;
485 if (gspca_dev->streaming)
486 setgain(gspca_dev);
487 return 0;
488}
489
490static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
491{
492 struct sd *sd = (struct sd *) gspca_dev;
493
494 *val = sd->gain;
495 return 0;
496}
497
498static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
499{
500 struct sd *sd = (struct sd *) gspca_dev;
501
502 sd->autogain = val;
503 /* when switching to autogain set defaults to make sure
504 we are on a valid point of the autogain gain /
505 exposure knee graph, and give this change time to
506 take effect before doing autogain. */
507 if (sd->autogain) {
508 sd->exposure = PAC207_EXPOSURE_DEFAULT;
509 sd->gain = PAC207_GAIN_DEFAULT;
510 if (gspca_dev->streaming) {
511 sd->autogain_ignore_frames =
512 PAC207_AUTOGAIN_IGNORE_FRAMES;
513 setexposure(gspca_dev);
514 setgain(gspca_dev);
515 }
516 }
517
518 return 0;
519}
520
521static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
522{
523 struct sd *sd = (struct sd *) gspca_dev;
524
525 *val = sd->autogain;
526 return 0;
527}
528
529/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300530static const struct sd_desc sd_desc = {
Hans de Goedee2997a72008-04-23 08:09:12 -0300531 .name = MODULE_NAME,
532 .ctrls = sd_ctrls,
533 .nctrls = ARRAY_SIZE(sd_ctrls),
534 .config = sd_config,
535 .open = sd_open,
536 .start = sd_start,
537 .stopN = sd_stopN,
538 .stop0 = sd_stop0,
539 .close = sd_close,
540 .dq_callback = pac207_do_auto_gain,
541 .pkt_scan = sd_pkt_scan,
542};
543
544/* -- module initialisation -- */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300545static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300546 {USB_DEVICE(0x041e, 0x4028)},
547 {USB_DEVICE(0x093a, 0x2460)},
548 {USB_DEVICE(0x093a, 0x2463)},
549 {USB_DEVICE(0x093a, 0x2464)},
550 {USB_DEVICE(0x093a, 0x2468)},
551 {USB_DEVICE(0x093a, 0x2470)},
552 {USB_DEVICE(0x093a, 0x2471)},
553 {USB_DEVICE(0x093a, 0x2472)},
554 {USB_DEVICE(0x2001, 0xf115)},
Hans de Goedee2997a72008-04-23 08:09:12 -0300555 {}
556};
557MODULE_DEVICE_TABLE(usb, device_table);
558
559/* -- device connect -- */
560static int sd_probe(struct usb_interface *intf,
561 const struct usb_device_id *id)
562{
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300563 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
564 THIS_MODULE);
Hans de Goedee2997a72008-04-23 08:09:12 -0300565}
566
567static struct usb_driver sd_driver = {
568 .name = MODULE_NAME,
569 .id_table = device_table,
570 .probe = sd_probe,
571 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300572#ifdef CONFIG_PM
573 .suspend = gspca_suspend,
574 .resume = gspca_resume,
575#endif
Hans de Goedee2997a72008-04-23 08:09:12 -0300576};
577
578/* -- module insert / remove -- */
579static int __init sd_mod_init(void)
580{
Hans de Goedee2997a72008-04-23 08:09:12 -0300581 if (usb_register(&sd_driver) < 0)
582 return -1;
Adrian Bunk903e10a2008-07-22 02:35:05 -0300583 PDEBUG(D_PROBE, "registered");
Hans de Goedee2997a72008-04-23 08:09:12 -0300584 return 0;
585}
586static void __exit sd_mod_exit(void)
587{
588 usb_deregister(&sd_driver);
589 PDEBUG(D_PROBE, "deregistered");
590}
591
592module_init(sd_mod_init);
593module_exit(sd_mod_exit);