blob: 620c9631629eda5d03b07d6e388524622b753f99 [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 Moine739570b2008-07-14 09:38:29 -0300184static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
Hans de Goedee2997a72008-04-23 08:09:12 -0300185 const u8 *buffer, u16 length)
186{
187 struct usb_device *udev = gspca_dev->dev;
188 int err;
Hans de Goedee2997a72008-04-23 08:09:12 -0300189
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300190 memcpy(gspca_dev->usb_buf, buffer, length);
Hans de Goedee2997a72008-04-23 08:09:12 -0300191
192 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
193 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300194 0x00, index,
195 gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
Hans de Goedee2997a72008-04-23 08:09:12 -0300196 if (err < 0)
197 PDEBUG(D_ERR,
198 "Failed to write registers to index 0x%04X, error %d)",
199 index, err);
200
201 return err;
202}
203
204
Adrian Bunk903e10a2008-07-22 02:35:05 -0300205static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
Hans de Goedee2997a72008-04-23 08:09:12 -0300206{
207 struct usb_device *udev = gspca_dev->dev;
208 int err;
209
210 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
211 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
212 value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
213 if (err)
214 PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
215 " value 0x%02X, error %d)", index, value, err);
216
217 return err;
218}
219
Adrian Bunk903e10a2008-07-22 02:35:05 -0300220static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
Hans de Goedee2997a72008-04-23 08:09:12 -0300221{
222 struct usb_device *udev = gspca_dev->dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300223 int res;
224
225 res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
226 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300227 0x00, index,
228 gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
Hans de Goedee2997a72008-04-23 08:09:12 -0300229 if (res < 0) {
230 PDEBUG(D_ERR,
231 "Failed to read a register (index 0x%04X, error %d)",
232 index, res);
233 return res;
234 }
235
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300236 return gspca_dev->usb_buf[0];
Hans de Goedee2997a72008-04-23 08:09:12 -0300237}
238
Hans de Goedee2997a72008-04-23 08:09:12 -0300239/* this function is called at probe time */
240static int sd_config(struct gspca_dev *gspca_dev,
241 const struct usb_device_id *id)
242{
Jean-Francois Moine4aa0d032008-05-04 06:46:21 -0300243 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300244 struct cam *cam;
245 u8 idreg[2];
246
247 idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
248 idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
249 idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
250 idreg[1] = idreg[1] & 0x0f;
251 PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
252 idreg[0], idreg[1]);
253
254 if (idreg[0] != 0x27) {
255 PDEBUG(D_PROBE, "Error invalid sensor ID!");
256 return -ENODEV;
257 }
258
259 pac207_write_reg(gspca_dev, 0x41, 0x00);
260 /* Bit_0=Image Format,
261 * Bit_1=LED,
262 * Bit_2=Compression test mode enable */
263 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
264 pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
265
266 PDEBUG(D_PROBE,
267 "Pixart PAC207BCA Image Processor and Control Chip detected"
268 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
269
270 cam = &gspca_dev->cam;
Hans de Goedee2997a72008-04-23 08:09:12 -0300271 cam->epaddr = 0x05;
272 cam->cam_mode = sif_mode;
273 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine4aa0d032008-05-04 06:46:21 -0300274 sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
275 sd->exposure = PAC207_EXPOSURE_DEFAULT;
276 sd->gain = PAC207_GAIN_DEFAULT;
Hans de Goedee2997a72008-04-23 08:09:12 -0300277
278 return 0;
279}
280
281/* this function is called at open time */
282static int sd_open(struct gspca_dev *gspca_dev)
283{
284 struct sd *sd = (struct sd *) gspca_dev;
285
Hans de Goedee2997a72008-04-23 08:09:12 -0300286 sd->autogain = 1;
Hans de Goedee2997a72008-04-23 08:09:12 -0300287 return 0;
288}
289
290/* -- start the camera -- */
291static void sd_start(struct gspca_dev *gspca_dev)
292{
293 struct sd *sd = (struct sd *) gspca_dev;
294 __u8 mode;
295
296 pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
297 pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
298 pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
299 pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
300 pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
301 pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
302 pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
303
304 /* Compression Balance */
305 if (gspca_dev->width == 176)
306 pac207_write_reg(gspca_dev, 0x4a, 0xff);
307 else
308 pac207_write_reg(gspca_dev, 0x4a, 0x88);
309 pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
310 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
311
312 /* PGA global gain (Bit 4-0) */
313 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
314 pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
315
316 mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300317 if (gspca_dev->width == 176) { /* 176x144 */
Hans de Goedee2997a72008-04-23 08:09:12 -0300318 mode |= 0x01;
319 PDEBUG(D_STREAM, "pac207_start mode 176x144");
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300320 } else { /* 352x288 */
Hans de Goedee2997a72008-04-23 08:09:12 -0300321 PDEBUG(D_STREAM, "pac207_start mode 352x288");
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300322 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300323 pac207_write_reg(gspca_dev, 0x41, mode);
324
325 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
326 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300327 msleep(10);
Hans de Goedee2997a72008-04-23 08:09:12 -0300328 pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
329
330 sd->sof_read = 0;
331 sd->autogain_ignore_frames = 0;
332 atomic_set(&sd->avg_lum, -1);
333}
334
335static void sd_stopN(struct gspca_dev *gspca_dev)
336{
337 pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
338 pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
339 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
340}
341
342static void sd_stop0(struct gspca_dev *gspca_dev)
343{
344}
345
346/* this function is called at close time */
347static void sd_close(struct gspca_dev *gspca_dev)
348{
349}
350
Hans de Goedee2997a72008-04-23 08:09:12 -0300351static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
352{
353 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300354 int avg_lum = atomic_read(&sd->avg_lum);
355
Hans de Goededcef3232008-07-10 10:40:53 -0300356 if (avg_lum == -1)
Hans de Goedee2997a72008-04-23 08:09:12 -0300357 return;
358
Hans de Goededcef3232008-07-10 10:40:53 -0300359 if (sd->autogain_ignore_frames > 0)
Hans de Goedee2997a72008-04-23 08:09:12 -0300360 sd->autogain_ignore_frames--;
Hans de Goededcef3232008-07-10 10:40:53 -0300361 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
362 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
363 PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
Hans de Goedee2997a72008-04-23 08:09:12 -0300364 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
Hans de Goedee2997a72008-04-23 08:09:12 -0300365}
366
Hans de Goede327c4ab2008-09-03 17:12:14 -0300367/* Include pac common sof detection functions */
368#include "pac_common.h"
Hans de Goedee2997a72008-04-23 08:09:12 -0300369
Hans de Goedee2997a72008-04-23 08:09:12 -0300370static void sd_pkt_scan(struct gspca_dev *gspca_dev,
371 struct gspca_frame *frame,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300372 __u8 *data,
Hans de Goedee2997a72008-04-23 08:09:12 -0300373 int len)
374{
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300375 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedee2997a72008-04-23 08:09:12 -0300376 unsigned char *sof;
Hans de Goedee2997a72008-04-23 08:09:12 -0300377
Hans de Goede327c4ab2008-09-03 17:12:14 -0300378 sof = pac_find_sof(gspca_dev, data, len);
Hans de Goedee2997a72008-04-23 08:09:12 -0300379 if (sof) {
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300380 int n;
381
Hans de Goedee2997a72008-04-23 08:09:12 -0300382 /* finish decoding current frame */
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300383 n = sof - data;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300384 if (n > sizeof pac_sof_marker)
385 n -= sizeof pac_sof_marker;
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300386 else
387 n = 0;
388 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
389 data, n);
390 sd->header_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300391 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
Hans de Goedee2997a72008-04-23 08:09:12 -0300392 len -= sof - data;
393 data = sof;
394 }
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300395 if (sd->header_read < 11) {
396 int needed;
Hans de Goedee2997a72008-04-23 08:09:12 -0300397
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300398 /* get average lumination from frame header (byte 5) */
399 if (sd->header_read < 5) {
400 needed = 5 - sd->header_read;
401 if (len >= needed)
402 atomic_set(&sd->avg_lum, data[needed - 1]);
403 }
404 /* skip the rest of the header */
405 needed = 11 - sd->header_read;
406 if (len <= needed) {
407 sd->header_read += len;
408 return;
409 }
410 data += needed;
411 len -= needed;
412 sd->header_read = 11;
413 }
Hans de Goedee2997a72008-04-23 08:09:12 -0300414
Hans de Goedeab8f12c2008-07-04 18:29:32 -0300415 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Hans de Goedee2997a72008-04-23 08:09:12 -0300416}
417
418static void setbrightness(struct gspca_dev *gspca_dev)
419{
420 struct sd *sd = (struct sd *) gspca_dev;
421
422 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
423 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
424 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
425}
426
427static void setexposure(struct gspca_dev *gspca_dev)
428{
429 struct sd *sd = (struct sd *) gspca_dev;
430
431 pac207_write_reg(gspca_dev, 0x02, sd->exposure);
432 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
433 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
434}
435
436static void setgain(struct gspca_dev *gspca_dev)
437{
438 struct sd *sd = (struct sd *) gspca_dev;
439
440 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
441 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
442 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
443}
444
445static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
446{
447 struct sd *sd = (struct sd *) gspca_dev;
448
449 sd->brightness = val;
450 if (gspca_dev->streaming)
451 setbrightness(gspca_dev);
452 return 0;
453}
454
455static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
456{
457 struct sd *sd = (struct sd *) gspca_dev;
458
459 *val = sd->brightness;
460 return 0;
461}
462
463static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
464{
465 struct sd *sd = (struct sd *) gspca_dev;
466
Hans de Goedee2997a72008-04-23 08:09:12 -0300467 sd->exposure = val;
468 if (gspca_dev->streaming)
469 setexposure(gspca_dev);
470 return 0;
471}
472
473static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
474{
475 struct sd *sd = (struct sd *) gspca_dev;
476
477 *val = sd->exposure;
478 return 0;
479}
480
481static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
482{
483 struct sd *sd = (struct sd *) gspca_dev;
484
Hans de Goedee2997a72008-04-23 08:09:12 -0300485 sd->gain = val;
486 if (gspca_dev->streaming)
487 setgain(gspca_dev);
488 return 0;
489}
490
491static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
492{
493 struct sd *sd = (struct sd *) gspca_dev;
494
495 *val = sd->gain;
496 return 0;
497}
498
499static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
500{
501 struct sd *sd = (struct sd *) gspca_dev;
502
503 sd->autogain = val;
504 /* when switching to autogain set defaults to make sure
505 we are on a valid point of the autogain gain /
506 exposure knee graph, and give this change time to
507 take effect before doing autogain. */
508 if (sd->autogain) {
509 sd->exposure = PAC207_EXPOSURE_DEFAULT;
510 sd->gain = PAC207_GAIN_DEFAULT;
511 if (gspca_dev->streaming) {
512 sd->autogain_ignore_frames =
513 PAC207_AUTOGAIN_IGNORE_FRAMES;
514 setexposure(gspca_dev);
515 setgain(gspca_dev);
516 }
517 }
518
519 return 0;
520}
521
522static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
523{
524 struct sd *sd = (struct sd *) gspca_dev;
525
526 *val = sd->autogain;
527 return 0;
528}
529
530/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300531static const struct sd_desc sd_desc = {
Hans de Goedee2997a72008-04-23 08:09:12 -0300532 .name = MODULE_NAME,
533 .ctrls = sd_ctrls,
534 .nctrls = ARRAY_SIZE(sd_ctrls),
535 .config = sd_config,
536 .open = sd_open,
537 .start = sd_start,
538 .stopN = sd_stopN,
539 .stop0 = sd_stop0,
540 .close = sd_close,
541 .dq_callback = pac207_do_auto_gain,
542 .pkt_scan = sd_pkt_scan,
543};
544
545/* -- module initialisation -- */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300546static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300547 {USB_DEVICE(0x041e, 0x4028)},
548 {USB_DEVICE(0x093a, 0x2460)},
549 {USB_DEVICE(0x093a, 0x2463)},
550 {USB_DEVICE(0x093a, 0x2464)},
551 {USB_DEVICE(0x093a, 0x2468)},
552 {USB_DEVICE(0x093a, 0x2470)},
553 {USB_DEVICE(0x093a, 0x2471)},
554 {USB_DEVICE(0x093a, 0x2472)},
555 {USB_DEVICE(0x2001, 0xf115)},
Hans de Goedee2997a72008-04-23 08:09:12 -0300556 {}
557};
558MODULE_DEVICE_TABLE(usb, device_table);
559
560/* -- device connect -- */
561static int sd_probe(struct usb_interface *intf,
562 const struct usb_device_id *id)
563{
Jean-Francois Moined43fa322008-06-12 10:58:58 -0300564 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
565 THIS_MODULE);
Hans de Goedee2997a72008-04-23 08:09:12 -0300566}
567
568static struct usb_driver sd_driver = {
569 .name = MODULE_NAME,
570 .id_table = device_table,
571 .probe = sd_probe,
572 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300573#ifdef CONFIG_PM
574 .suspend = gspca_suspend,
575 .resume = gspca_resume,
576#endif
Hans de Goedee2997a72008-04-23 08:09:12 -0300577};
578
579/* -- module insert / remove -- */
580static int __init sd_mod_init(void)
581{
Hans de Goedee2997a72008-04-23 08:09:12 -0300582 if (usb_register(&sd_driver) < 0)
583 return -1;
Adrian Bunk903e10a2008-07-22 02:35:05 -0300584 PDEBUG(D_PROBE, "registered");
Hans de Goedee2997a72008-04-23 08:09:12 -0300585 return 0;
586}
587static void __exit sd_mod_exit(void)
588{
589 usb_deregister(&sd_driver);
590 PDEBUG(D_PROBE, "deregistered");
591}
592
593module_init(sd_mod_init);
594module_exit(sd_mod_exit);