blob: a15bccad947bb6368edfe0f8e292f65cba0ec1c5 [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
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300276/* this function is called at probe and resume time */
277static int sd_init(struct gspca_dev *gspca_dev)
Hans de Goedee2997a72008-04-23 08:09:12 -0300278{
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
Hans de Goedee2997a72008-04-23 08:09:12 -0300341static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
342{
343 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300344 int avg_lum = atomic_read(&sd->avg_lum);
345
Hans de Goededcef3232008-07-10 10:40:53 -0300346 if (avg_lum == -1)
Hans de Goedee2997a72008-04-23 08:09:12 -0300347 return;
348
Hans de Goededcef3232008-07-10 10:40:53 -0300349 if (sd->autogain_ignore_frames > 0)
Hans de Goedee2997a72008-04-23 08:09:12 -0300350 sd->autogain_ignore_frames--;
Hans de Goededcef3232008-07-10 10:40:53 -0300351 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
352 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
353 PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
Hans de Goedee2997a72008-04-23 08:09:12 -0300354 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
Hans de Goedee2997a72008-04-23 08:09:12 -0300355}
356
Hans de Goede327c4ab2008-09-03 17:12:14 -0300357/* Include pac common sof detection functions */
358#include "pac_common.h"
Hans de Goedee2997a72008-04-23 08:09:12 -0300359
Hans de Goedee2997a72008-04-23 08:09:12 -0300360static void sd_pkt_scan(struct gspca_dev *gspca_dev,
361 struct gspca_frame *frame,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300362 __u8 *data,
Hans de Goedee2997a72008-04-23 08:09:12 -0300363 int len)
364{
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300365 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300366 unsigned char *sof;
Hans de Goedee2997a72008-04-23 08:09:12 -0300367
Hans de Goede327c4ab2008-09-03 17:12:14 -0300368 sof = pac_find_sof(gspca_dev, data, len);
Hans de Goedee2997a72008-04-23 08:09:12 -0300369 if (sof) {
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300370 int n;
371
Hans de Goedee2997a72008-04-23 08:09:12 -0300372 /* finish decoding current frame */
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300373 n = sof - data;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300374 if (n > sizeof pac_sof_marker)
375 n -= sizeof pac_sof_marker;
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300376 else
377 n = 0;
378 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
379 data, n);
380 sd->header_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300381 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
Hans de Goedee2997a72008-04-23 08:09:12 -0300382 len -= sof - data;
383 data = sof;
384 }
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300385 if (sd->header_read < 11) {
386 int needed;
Hans de Goedee2997a72008-04-23 08:09:12 -0300387
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300388 /* get average lumination from frame header (byte 5) */
389 if (sd->header_read < 5) {
390 needed = 5 - sd->header_read;
391 if (len >= needed)
392 atomic_set(&sd->avg_lum, data[needed - 1]);
393 }
394 /* skip the rest of the header */
395 needed = 11 - sd->header_read;
396 if (len <= needed) {
397 sd->header_read += len;
398 return;
399 }
400 data += needed;
401 len -= needed;
402 sd->header_read = 11;
403 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300404
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300405 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Hans de Goedee2997a72008-04-23 08:09:12 -0300406}
407
408static void setbrightness(struct gspca_dev *gspca_dev)
409{
410 struct sd *sd = (struct sd *) gspca_dev;
411
412 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
413 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
414 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
415}
416
417static void setexposure(struct gspca_dev *gspca_dev)
418{
419 struct sd *sd = (struct sd *) gspca_dev;
420
421 pac207_write_reg(gspca_dev, 0x02, sd->exposure);
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 setgain(struct gspca_dev *gspca_dev)
427{
428 struct sd *sd = (struct sd *) gspca_dev;
429
430 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
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 int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
436{
437 struct sd *sd = (struct sd *) gspca_dev;
438
439 sd->brightness = val;
440 if (gspca_dev->streaming)
441 setbrightness(gspca_dev);
442 return 0;
443}
444
445static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
446{
447 struct sd *sd = (struct sd *) gspca_dev;
448
449 *val = sd->brightness;
450 return 0;
451}
452
453static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
454{
455 struct sd *sd = (struct sd *) gspca_dev;
456
Hans de Goedee2997a72008-04-23 08:09:12 -0300457 sd->exposure = val;
458 if (gspca_dev->streaming)
459 setexposure(gspca_dev);
460 return 0;
461}
462
463static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
464{
465 struct sd *sd = (struct sd *) gspca_dev;
466
467 *val = sd->exposure;
468 return 0;
469}
470
471static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
472{
473 struct sd *sd = (struct sd *) gspca_dev;
474
Hans de Goedee2997a72008-04-23 08:09:12 -0300475 sd->gain = val;
476 if (gspca_dev->streaming)
477 setgain(gspca_dev);
478 return 0;
479}
480
481static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
482{
483 struct sd *sd = (struct sd *) gspca_dev;
484
485 *val = sd->gain;
486 return 0;
487}
488
489static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
490{
491 struct sd *sd = (struct sd *) gspca_dev;
492
493 sd->autogain = val;
494 /* when switching to autogain set defaults to make sure
495 we are on a valid point of the autogain gain /
496 exposure knee graph, and give this change time to
497 take effect before doing autogain. */
498 if (sd->autogain) {
499 sd->exposure = PAC207_EXPOSURE_DEFAULT;
500 sd->gain = PAC207_GAIN_DEFAULT;
501 if (gspca_dev->streaming) {
502 sd->autogain_ignore_frames =
503 PAC207_AUTOGAIN_IGNORE_FRAMES;
504 setexposure(gspca_dev);
505 setgain(gspca_dev);
506 }
507 }
508
509 return 0;
510}
511
512static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
513{
514 struct sd *sd = (struct sd *) gspca_dev;
515
516 *val = sd->autogain;
517 return 0;
518}
519
520/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300521static const struct sd_desc sd_desc = {
Hans de Goedee2997a72008-04-23 08:09:12 -0300522 .name = MODULE_NAME,
523 .ctrls = sd_ctrls,
524 .nctrls = ARRAY_SIZE(sd_ctrls),
525 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300526 .init = sd_init,
Hans de Goedee2997a72008-04-23 08:09:12 -0300527 .start = sd_start,
528 .stopN = sd_stopN,
Hans de Goedee2997a72008-04-23 08:09:12 -0300529 .dq_callback = pac207_do_auto_gain,
530 .pkt_scan = sd_pkt_scan,
531};
532
533/* -- module initialisation -- */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300534static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300535 {USB_DEVICE(0x041e, 0x4028)},
536 {USB_DEVICE(0x093a, 0x2460)},
537 {USB_DEVICE(0x093a, 0x2463)},
538 {USB_DEVICE(0x093a, 0x2464)},
539 {USB_DEVICE(0x093a, 0x2468)},
540 {USB_DEVICE(0x093a, 0x2470)},
541 {USB_DEVICE(0x093a, 0x2471)},
542 {USB_DEVICE(0x093a, 0x2472)},
543 {USB_DEVICE(0x2001, 0xf115)},
Hans de Goedee2997a72008-04-23 08:09:12 -0300544 {}
545};
546MODULE_DEVICE_TABLE(usb, device_table);
547
548/* -- device connect -- */
549static int sd_probe(struct usb_interface *intf,
550 const struct usb_device_id *id)
551{
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300552 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
553 THIS_MODULE);
Hans de Goedee2997a72008-04-23 08:09:12 -0300554}
555
556static struct usb_driver sd_driver = {
557 .name = MODULE_NAME,
558 .id_table = device_table,
559 .probe = sd_probe,
560 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300561#ifdef CONFIG_PM
562 .suspend = gspca_suspend,
563 .resume = gspca_resume,
564#endif
Hans de Goedee2997a72008-04-23 08:09:12 -0300565};
566
567/* -- module insert / remove -- */
568static int __init sd_mod_init(void)
569{
Hans de Goedee2997a72008-04-23 08:09:12 -0300570 if (usb_register(&sd_driver) < 0)
571 return -1;
Adrian Bunk903e10a2008-07-22 02:35:05 -0300572 PDEBUG(D_PROBE, "registered");
Hans de Goedee2997a72008-04-23 08:09:12 -0300573 return 0;
574}
575static void __exit sd_mod_exit(void)
576{
577 usb_deregister(&sd_driver);
578 PDEBUG(D_PROBE, "deregistered");
579}
580
581module_init(sd_mod_init);
582module_exit(sd_mod_exit);