aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca/pac207.c
diff options
context:
space:
mode:
authorHans de Goede <j.w.r.degoede@hhs.nl>2008-04-23 07:09:12 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-07-20 06:14:32 -0400
commite2997a72ddfafc25bd0c8f1f52bcf41979d5a559 (patch)
treebe39e1c2f946a5d3c2e82fe7a2d663f54fda11d4 /drivers/media/video/gspca/pac207.c
parent63eb9546dcb5e9dc39ab88a603dede8fdd18e717 (diff)
V4L/DVB (8153): Subdriver pac207 added and minor changes.
pac207 added. Check status on mutex lock. Call back on frame dequeue. Free the resources on last close only. Avoid URB and ISOC errors on close. Signed-off-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/gspca/pac207.c')
-rw-r--r--drivers/media/video/gspca/pac207.c939
1 files changed, 939 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
new file mode 100644
index 000000000000..ac16c7352892
--- /dev/null
+++ b/drivers/media/video/gspca/pac207.c
@@ -0,0 +1,939 @@
1/*
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
30#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 0, 30)
31static const char version[] = "0.0.30";
32
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
43#define PAC207_EXPOSURE_MIN 4
44#define PAC207_EXPOSURE_MAX 26
45#define PAC207_EXPOSURE_DEFAULT 4 /* power on default: 3 ?? */
46#define PAC207_EXPOSURE_KNEE 11 /* 4 = 30 fps, 11 = 8, 15 = 6 */
47
48#define PAC207_GAIN_MIN 0
49#define PAC207_GAIN_MAX 31
50#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */
51#define PAC207_GAIN_KNEE 20
52
53#define PAC207_AUTOGAIN_DEADZONE 30
54/* We calculating the autogain at the end of the transfer of a frame, at this
55 moment a frame with the old settings is being transmitted, and a frame is
56 being captured with the old settings. So if we adjust the autogain we must
57 ignore atleast the 2 next frames for the new settings to come into effect
58 before doing any other adjustments */
59#define PAC207_AUTOGAIN_IGNORE_FRAMES 3
60
61enum pac207_line_state {
62 LINE_HEADER1,
63 LINE_HEADER2,
64 LINE_UNCOMPRESSED,
65 LINE_COMPRESSED,
66};
67
68struct pac207_decoder_state {
69 /* generic state */
70 u16 line_read;
71 u16 line_marker;
72 u8 line_state;
73 u8 header_read;
74 /* compression state */
75 u16 processed_bytes;
76 u8 remaining_bits;
77 s8 no_remaining_bits;
78 u8 get_abs;
79 u8 discard_byte;
80 u8 line_decode_buf[352];
81};
82
83/* specific webcam descriptor */
84struct sd {
85 struct gspca_dev gspca_dev; /* !! must be the first item */
86
87 struct pac207_decoder_state decoder_state;
88
89 u8 mode;
90
91 u8 brightness;
92 u8 exposure;
93 u8 autogain;
94 u8 gain;
95
96 u8 sof_read;
97 u8 autogain_ignore_frames;
98
99 atomic_t avg_lum;
100};
101
102/* V4L2 controls supported by the driver */
103static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
104static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
105static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
106static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
107static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
108static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
109static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
110static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
111
112static struct ctrl sd_ctrls[] = {
113#define SD_BRIGHTNESS 0
114 {
115 {
116 .id = V4L2_CID_BRIGHTNESS,
117 .type = V4L2_CTRL_TYPE_INTEGER,
118 .name = "Brightness",
119 .minimum = PAC207_BRIGHTNESS_MIN,
120 .maximum = PAC207_BRIGHTNESS_MAX,
121 .step = 1,
122 .default_value = PAC207_BRIGHTNESS_DEFAULT,
123 .flags = 0,
124 },
125 .set = sd_setbrightness,
126 .get = sd_getbrightness,
127 },
128#define SD_EXPOSURE 1
129 {
130 {
131 .id = V4L2_CID_EXPOSURE,
132 .type = V4L2_CTRL_TYPE_INTEGER,
133 .name = "exposure",
134 .minimum = PAC207_EXPOSURE_MIN,
135 .maximum = PAC207_EXPOSURE_MAX,
136 .step = 1,
137 .default_value = PAC207_EXPOSURE_DEFAULT,
138 .flags = 0,
139 },
140 .set = sd_setexposure,
141 .get = sd_getexposure,
142 },
143#define SD_AUTOGAIN 2
144 {
145 {
146 .id = V4L2_CID_AUTOGAIN,
147 .type = V4L2_CTRL_TYPE_BOOLEAN,
148 .name = "Auto Gain",
149 .minimum = 0,
150 .maximum = 1,
151 .step = 1,
152 .default_value = 1,
153 .flags = 0,
154 },
155 .set = sd_setautogain,
156 .get = sd_getautogain,
157 },
158#define SD_GAIN 3
159 {
160 {
161 .id = V4L2_CID_GAIN,
162 .type = V4L2_CTRL_TYPE_INTEGER,
163 .name = "gain",
164 .minimum = PAC207_GAIN_MIN,
165 .maximum = PAC207_GAIN_MAX,
166 .step = 1,
167 .default_value = PAC207_GAIN_DEFAULT,
168 .flags = 0,
169 },
170 .set = sd_setgain,
171 .get = sd_getgain,
172 },
173};
174
175static struct cam_mode sif_mode[] = {
176 {V4L2_PIX_FMT_SBGGR8, 176, 144, 1},
177 {V4L2_PIX_FMT_SBGGR8, 352, 288, 0},
178};
179
180static const __u8 pac207_sensor_init[][8] = {
181 {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
182 {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
183 {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
184 {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
185 {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
186};
187
188 /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
189static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
190
191static const char pac207_sof_marker[5] = { 0xff, 0xff, 0x00, 0xff, 0x96 };
192
193int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
194 const u8 *buffer, u16 length)
195{
196 struct usb_device *udev = gspca_dev->dev;
197 int err;
198 u8 kbuf[8];
199
200 memcpy(kbuf, buffer, length);
201
202 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
203 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
204 0x00, index, kbuf, length, PAC207_CTRL_TIMEOUT);
205 if (err < 0)
206 PDEBUG(D_ERR,
207 "Failed to write registers to index 0x%04X, error %d)",
208 index, err);
209
210 return err;
211}
212
213
214int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
215{
216 struct usb_device *udev = gspca_dev->dev;
217 int err;
218
219 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
220 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
221 value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
222 if (err)
223 PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
224 " value 0x%02X, error %d)", index, value, err);
225
226 return err;
227}
228
229
230int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
231{
232 struct usb_device *udev = gspca_dev->dev;
233 u8 buff;
234 int res;
235
236 res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
237 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
238 0x00, index, &buff, 1, PAC207_CTRL_TIMEOUT);
239 if (res < 0) {
240 PDEBUG(D_ERR,
241 "Failed to read a register (index 0x%04X, error %d)",
242 index, res);
243 return res;
244 }
245
246 return buff;
247}
248
249
250/* this function is called at probe time */
251static int sd_config(struct gspca_dev *gspca_dev,
252 const struct usb_device_id *id)
253{
254 struct cam *cam;
255 u8 idreg[2];
256
257 idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
258 idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
259 idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
260 idreg[1] = idreg[1] & 0x0f;
261 PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
262 idreg[0], idreg[1]);
263
264 if (idreg[0] != 0x27) {
265 PDEBUG(D_PROBE, "Error invalid sensor ID!");
266 return -ENODEV;
267 }
268
269 pac207_write_reg(gspca_dev, 0x41, 0x00);
270 /* Bit_0=Image Format,
271 * Bit_1=LED,
272 * Bit_2=Compression test mode enable */
273 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
274 pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
275
276 PDEBUG(D_PROBE,
277 "Pixart PAC207BCA Image Processor and Control Chip detected"
278 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
279
280 cam = &gspca_dev->cam;
281 cam->dev_name = (char *) id->driver_info;
282 cam->epaddr = 0x05;
283 cam->cam_mode = sif_mode;
284 cam->nmodes = ARRAY_SIZE(sif_mode);
285
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
294 sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
295 sd->exposure = PAC207_EXPOSURE_DEFAULT;
296 sd->gain = PAC207_GAIN_DEFAULT;
297 sd->autogain = 1;
298
299 return 0;
300}
301
302/* -- start the camera -- */
303static void sd_start(struct gspca_dev *gspca_dev)
304{
305 struct sd *sd = (struct sd *) gspca_dev;
306 __u8 mode;
307
308 pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
309 pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
310 pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
311 pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
312 pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
313 pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
314 pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
315
316 /* Compression Balance */
317 if (gspca_dev->width == 176)
318 pac207_write_reg(gspca_dev, 0x4a, 0xff);
319 else
320 pac207_write_reg(gspca_dev, 0x4a, 0x88);
321 pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
322 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
323
324 /* PGA global gain (Bit 4-0) */
325 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
326 pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
327
328 mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
329 if (gspca_dev->width == 176) { /* 176x144 */
330 mode |= 0x01;
331 PDEBUG(D_STREAM, "pac207_start mode 176x144");
332 } else/* 352x288 */
333 PDEBUG(D_STREAM, "pac207_start mode 352x288");
334 pac207_write_reg(gspca_dev, 0x41, mode);
335
336 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
337 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
338 udelay(1000); /* taken from gspca */
339 pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
340
341 sd->sof_read = 0;
342 sd->autogain_ignore_frames = 0;
343 atomic_set(&sd->avg_lum, -1);
344}
345
346static void sd_stopN(struct gspca_dev *gspca_dev)
347{
348 pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
349 pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
350 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
351}
352
353static void sd_stop0(struct gspca_dev *gspca_dev)
354{
355}
356
357/* this function is called at close time */
358static void sd_close(struct gspca_dev *gspca_dev)
359{
360}
361
362/* -- convert pixart frames to Bayer -- */
363/* Sonix decompressor struct B.S.(2004) */
364static struct {
365 u8 is_abs;
366 u8 len;
367 s8 val;
368} table[256];
369
370void init_pixart_decoder(void)
371{
372 int i, is_abs, val, len;
373
374 for (i = 0; i < 256; i++) {
375 is_abs = 0;
376 val = 0;
377 len = 0;
378 if ((i & 0xC0) == 0) {
379 /* code 00 */
380 val = 0;
381 len = 2;
382 } else if ((i & 0xC0) == 0x40) {
383 /* code 01 */
384 val = -5;
385 len = 2;
386 } else if ((i & 0xC0) == 0x80) {
387 /* code 10 */
388 val = 5;
389 len = 2;
390 } else if ((i & 0xF0) == 0xC0) {
391 /* code 1100 */
392 val = -10;
393 len = 4;
394 } else if ((i & 0xF0) == 0xD0) {
395 /* code 1101 */
396 val = 10;
397 len = 4;
398 } else if ((i & 0xF8) == 0xE0) {
399 /* code 11100 */
400 val = -15;
401 len = 5;
402 } else if ((i & 0xF8) == 0xE8) {
403 /* code 11101 */
404 val = 15;
405 len = 5;
406 } else if ((i & 0xFC) == 0xF0) {
407 /* code 111100 */
408 val = -20;
409 len = 6;
410 } else if ((i & 0xFC) == 0xF4) {
411 /* code 111101 */
412 val = 20;
413 len = 6;
414 } else if ((i & 0xF8) == 0xF8) {
415 /* code 11111xxxxxx */
416 is_abs = 1;
417 val = 0;
418 len = 5;
419 }
420 table[i].is_abs = is_abs;
421 table[i].val = val;
422 table[i].len = len;
423 }
424}
425
426/* auto gain and exposure algorithm based on the knee algorithm described here:
427 http://ytse.tricolour.net/docs/LowLightOptimization.html */
428static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
429{
430 struct sd *sd = (struct sd *) gspca_dev;
431 int i, steps, desired_avg_lum;
432 int orig_gain = sd->gain;
433 int orig_exposure = sd->exposure;
434 int avg_lum = atomic_read(&sd->avg_lum);
435
436 if (!sd->autogain || avg_lum == -1)
437 return;
438
439 if (sd->autogain_ignore_frames > 0) {
440 sd->autogain_ignore_frames--;
441 return;
442 }
443
444 /* correct desired lumination for the configured brightness */
445 desired_avg_lum = 100 + sd->brightness / 2;
446
447 /* If we are of a multiple of deadzone, do multiple step to reach the
448 desired lumination fast (with the risc of a slight overshoot) */
449 steps = abs(desired_avg_lum - avg_lum) / PAC207_AUTOGAIN_DEADZONE;
450
451 for (i = 0; i < steps; i++) {
452 if (avg_lum > desired_avg_lum) {
453 if (sd->gain > PAC207_GAIN_KNEE) {
454 sd->gain--;
455 } else if (sd->exposure > PAC207_EXPOSURE_KNEE) {
456 sd->exposure--;
457 } else if (sd->gain > PAC207_GAIN_DEFAULT) {
458 sd->gain--;
459 } else if (sd->exposure > PAC207_EXPOSURE_MIN) {
460 sd->exposure--;
461 } else if (sd->gain > PAC207_GAIN_MIN) {
462 sd->gain--;
463 } else
464 break;
465 } else {
466 if (sd->gain < PAC207_GAIN_DEFAULT) {
467 sd->gain++;
468 } else if (sd->exposure < PAC207_EXPOSURE_KNEE) {
469 sd->exposure++;
470 } else if (sd->gain < PAC207_GAIN_KNEE) {
471 sd->gain++;
472 } else if (sd->exposure < PAC207_EXPOSURE_MAX) {
473 sd->exposure++;
474 } else if (sd->gain < PAC207_GAIN_MAX) {
475 sd->gain++;
476 } else
477 break;
478 }
479 }
480
481 if (sd->exposure != orig_exposure || sd->gain != orig_gain) {
482 if (sd->exposure != orig_exposure)
483 pac207_write_reg(gspca_dev, 0x0002, sd->exposure);
484 if (sd->gain != orig_gain)
485 pac207_write_reg(gspca_dev, 0x000e, sd->gain);
486 pac207_write_reg(gspca_dev, 0x13, 0x01); /* load reg to sen */
487 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
488 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
489 }
490}
491
492static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
493 unsigned char *m, int len)
494{
495 struct sd *sd = (struct sd *) gspca_dev;
496 int i;
497
498 /* Search for the SOF marker (fixed part) in the header */
499 for (i = 0; i < len; i++) {
500 if (m[i] == pac207_sof_marker[sd->sof_read]) {
501 sd->sof_read++;
502 if (sd->sof_read == sizeof(pac207_sof_marker)) {
503 PDEBUG(D_STREAM,
504 "SOF found, bytes to analyze: %u."
505 " Frame starts at byte #%u",
506 len, i + 1);
507 sd->sof_read = 0;
508 return m + i + 1;
509 }
510 } else
511 sd->sof_read = 0;
512 }
513
514 return NULL;
515}
516
517static int pac207_decompress_row(struct gspca_dev *gspca_dev,
518 struct gspca_frame *f, unsigned char *cdata, int len)
519{
520 struct sd *sd = (struct sd *) gspca_dev;
521 struct pac207_decoder_state *decoder_state = &sd->decoder_state;
522 unsigned char *outp = decoder_state->line_decode_buf +
523 decoder_state->line_read;
524 int val, bitlen, bitpos = -decoder_state->no_remaining_bits;
525 u8 code;
526
527 /* first two pixels are stored as raw 8-bit */
528 while (decoder_state->line_read < 2) {
529 *outp++ = *cdata++;
530 decoder_state->line_read++;
531 len--;
532 if (len == 0)
533 return 0;
534 }
535
536 while (decoder_state->line_read < gspca_dev->width) {
537 if (bitpos < 0) {
538 code = decoder_state->remaining_bits << (8 + bitpos) |
539 cdata[0] >> -bitpos;
540 } else {
541 u8 *addr = cdata + bitpos / 8;
542 code = addr[0] << (bitpos & 7) |
543 addr[1] >> (8 - (bitpos & 7));
544 }
545
546 bitlen = decoder_state->get_abs ?
547 6 : table[code].len;
548
549 /* Stop decompressing if we're out of input data */
550 if ((bitpos + bitlen) > (len * 8))
551 break;
552
553 if (decoder_state->get_abs) {
554 *outp++ = code & 0xFC;
555 decoder_state->line_read++;
556 decoder_state->get_abs = 0;
557 } else {
558 if (table[code].is_abs)
559 decoder_state->get_abs = 1;
560 else {
561 /* relative to left pixel */
562 val = outp[-2] +
563 table[code].val;
564 if (val > 0xff)
565 val = 0xff;
566 else if (val < 0)
567 val = 0;
568 *outp++ = val;
569 decoder_state->line_read++;
570 }
571 }
572 bitpos += bitlen;
573 }
574
575 if (decoder_state->line_read == gspca_dev->width) {
576 int compressed_line_len;
577
578 gspca_frame_add(gspca_dev, INTER_PACKET, f,
579 decoder_state->line_decode_buf,
580 gspca_dev->width);
581
582 /* completely decompressed line, round pos to nearest word */
583 compressed_line_len = ((decoder_state->processed_bytes * 8 +
584 bitpos + 15) / 16) * 2;
585
586 len -= compressed_line_len - decoder_state->processed_bytes;
587 if (len < 0) {
588 decoder_state->discard_byte = 1;
589 len = 0;
590 }
591 } else {
592 decoder_state->processed_bytes += len;
593 decoder_state->remaining_bits = cdata[bitpos/8];
594 decoder_state->no_remaining_bits = (8 - bitpos) & 7;
595 len = 0;
596 }
597
598 return len;
599}
600
601static void pac207_decode_line_init(struct gspca_dev *gspca_dev)
602{
603 struct sd *sd = (struct sd *) gspca_dev;
604 struct pac207_decoder_state *decoder_state = &sd->decoder_state;
605
606 decoder_state->line_read = 0;
607 decoder_state->line_state = LINE_HEADER1;
608 decoder_state->processed_bytes = 0;
609 decoder_state->no_remaining_bits = 0;
610 decoder_state->get_abs = 0;
611}
612
613static void pac207_decode_frame_init(struct gspca_dev *gspca_dev)
614{
615 struct sd *sd = (struct sd *) gspca_dev;
616 struct pac207_decoder_state *decoder_state = &sd->decoder_state;
617
618 decoder_state->header_read = 0;
619 decoder_state->discard_byte = 0;
620
621 pac207_decode_line_init(gspca_dev);
622}
623
624static int pac207_decode_frame_data(struct gspca_dev *gspca_dev,
625 struct gspca_frame *f, unsigned char *data, int len)
626{
627 struct sd *sd = (struct sd *) gspca_dev;
628 struct pac207_decoder_state *decoder_state = &sd->decoder_state;
629 int needed = 0;
630
631 /* first 11 bytes after sof marker: frame header */
632 if (decoder_state->header_read < 11) {
633 /* get average lumination from frame header (byte 5) */
634 if (decoder_state->header_read < 5) {
635 needed = 5 - decoder_state->header_read;
636 if (len >= needed)
637 atomic_set(&sd->avg_lum, data[needed-1]);
638 }
639 /* skip the rest of the header */
640 needed = 11 - decoder_state->header_read;
641 if (len <= needed) {
642 decoder_state->header_read += len;
643 return 0;
644 }
645 data += needed;
646 len -= needed;
647 decoder_state->header_read = 11;
648 }
649
650 while (len) {
651 if (decoder_state->discard_byte) {
652 data++;
653 len--;
654 decoder_state->discard_byte = 0;
655 continue;
656 }
657
658 switch (decoder_state->line_state) {
659 case LINE_HEADER1:
660 decoder_state->line_marker = data[0] << 8;
661 decoder_state->line_state = LINE_HEADER2;
662 needed = 1;
663 break;
664 case LINE_HEADER2:
665 decoder_state->line_marker |= data[0];
666 switch (decoder_state->line_marker) {
667 case 0x0FF0:
668 decoder_state->line_state = LINE_UNCOMPRESSED;
669 break;
670 case 0x1EE1:
671 decoder_state->line_state = LINE_COMPRESSED;
672 break;
673 default:
674 PDEBUG(D_STREAM,
675 "Error unknown line-header %04X",
676 (int) decoder_state->line_marker);
677 gspca_dev->last_packet_type = DISCARD_PACKET;
678 return 0;
679 }
680 needed = 1;
681 break;
682 case LINE_UNCOMPRESSED:
683 needed = gspca_dev->width - decoder_state->line_read;
684 if (needed > len)
685 needed = len;
686 gspca_frame_add(gspca_dev, INTER_PACKET, f, data,
687 needed);
688 decoder_state->line_read += needed;
689 break;
690 case LINE_COMPRESSED:
691 needed = len -
692 pac207_decompress_row(gspca_dev, f, data, len);
693 break;
694 }
695
696 data += needed;
697 len -= needed;
698
699 if (decoder_state->line_read == gspca_dev->width) {
700 if ((f->data_end - f->data) ==
701 (gspca_dev->width * gspca_dev->height)) {
702 /* eureka we've got a frame */
703 return 1;
704 }
705 pac207_decode_line_init(gspca_dev);
706 }
707 }
708
709 return 0;
710}
711
712static void sd_pkt_scan(struct gspca_dev *gspca_dev,
713 struct gspca_frame *frame,
714 unsigned char *data,
715 int len)
716{
717 unsigned char *sof;
718 int n;
719
720 sof = pac207_find_sof(gspca_dev, data, len);
721
722 if (sof) {
723 /* finish decoding current frame */
724 if (gspca_dev->last_packet_type == INTER_PACKET) {
725 n = sof - data;
726 if (n > sizeof(pac207_sof_marker))
727 n -= sizeof(pac207_sof_marker);
728 else
729 n = 0;
730 n = pac207_decode_frame_data(gspca_dev, frame,
731 data, n);
732 if (n)
733 frame = gspca_frame_add(gspca_dev,
734 LAST_PACKET,
735 frame,
736 NULL,
737 0);
738 else
739 PDEBUG(D_STREAM, "Incomplete frame");
740 }
741 pac207_decode_frame_init(gspca_dev);
742 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL,
743 0);
744 len -= sof - data;
745 data = sof;
746 }
747
748 if (gspca_dev->last_packet_type == DISCARD_PACKET)
749 return;
750
751 n = pac207_decode_frame_data(gspca_dev, frame, data, len);
752 if (n)
753 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
754 frame, NULL, 0);
755}
756
757static void setbrightness(struct gspca_dev *gspca_dev)
758{
759 struct sd *sd = (struct sd *) gspca_dev;
760
761 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
762 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
763 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
764}
765
766static void setexposure(struct gspca_dev *gspca_dev)
767{
768 struct sd *sd = (struct sd *) gspca_dev;
769
770 pac207_write_reg(gspca_dev, 0x02, sd->exposure);
771 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
772 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
773}
774
775static void setgain(struct gspca_dev *gspca_dev)
776{
777 struct sd *sd = (struct sd *) gspca_dev;
778
779 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
780 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
781 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
782}
783
784static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
785{
786 struct sd *sd = (struct sd *) gspca_dev;
787
788 sd->brightness = val;
789 if (gspca_dev->streaming)
790 setbrightness(gspca_dev);
791 return 0;
792}
793
794static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
795{
796 struct sd *sd = (struct sd *) gspca_dev;
797
798 *val = sd->brightness;
799 return 0;
800}
801
802static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
803{
804 struct sd *sd = (struct sd *) gspca_dev;
805
806 /* don't allow mucking with exposure when using autogain */
807 if (sd->autogain)
808 return -EINVAL;
809
810 sd->exposure = val;
811 if (gspca_dev->streaming)
812 setexposure(gspca_dev);
813 return 0;
814}
815
816static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
817{
818 struct sd *sd = (struct sd *) gspca_dev;
819
820 *val = sd->exposure;
821 return 0;
822}
823
824static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
825{
826 struct sd *sd = (struct sd *) gspca_dev;
827
828 /* don't allow mucking with gain when using autogain */
829 if (sd->autogain)
830 return -EINVAL;
831
832 sd->gain = val;
833 if (gspca_dev->streaming)
834 setgain(gspca_dev);
835 return 0;
836}
837
838static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
839{
840 struct sd *sd = (struct sd *) gspca_dev;
841
842 *val = sd->gain;
843 return 0;
844}
845
846static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
847{
848 struct sd *sd = (struct sd *) gspca_dev;
849
850 sd->autogain = val;
851 /* when switching to autogain set defaults to make sure
852 we are on a valid point of the autogain gain /
853 exposure knee graph, and give this change time to
854 take effect before doing autogain. */
855 if (sd->autogain) {
856 sd->exposure = PAC207_EXPOSURE_DEFAULT;
857 sd->gain = PAC207_GAIN_DEFAULT;
858 if (gspca_dev->streaming) {
859 sd->autogain_ignore_frames =
860 PAC207_AUTOGAIN_IGNORE_FRAMES;
861 setexposure(gspca_dev);
862 setgain(gspca_dev);
863 }
864 }
865
866 return 0;
867}
868
869static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
870{
871 struct sd *sd = (struct sd *) gspca_dev;
872
873 *val = sd->autogain;
874 return 0;
875}
876
877/* sub-driver description */
878static struct sd_desc sd_desc = {
879 .name = MODULE_NAME,
880 .ctrls = sd_ctrls,
881 .nctrls = ARRAY_SIZE(sd_ctrls),
882 .config = sd_config,
883 .open = sd_open,
884 .start = sd_start,
885 .stopN = sd_stopN,
886 .stop0 = sd_stop0,
887 .close = sd_close,
888 .dq_callback = pac207_do_auto_gain,
889 .pkt_scan = sd_pkt_scan,
890};
891
892/* -- module initialisation -- */
893#define DVNM(name) .driver_info = (kernel_ulong_t) name
894static __devinitdata struct usb_device_id device_table[] = {
895 {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
896 {USB_DEVICE(0x093a, 0x2460), DVNM("PAC207 Qtec Webcam 100")},
897 {USB_DEVICE(0x093a, 0x2463), DVNM("Philips spc200nc pac207")},
898 {USB_DEVICE(0x093a, 0x2464), DVNM("Labtec Webcam 1200")},
899 {USB_DEVICE(0x093a, 0x2468), DVNM("PAC207")},
900 {USB_DEVICE(0x093a, 0x2470), DVNM("Genius GF112")},
901 {USB_DEVICE(0x093a, 0x2471), DVNM("PAC207 Genius VideoCam ge111")},
902 {USB_DEVICE(0x093a, 0x2472), DVNM("PAC207 Genius VideoCam ge110")},
903 {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")},
904 {}
905};
906MODULE_DEVICE_TABLE(usb, device_table);
907
908/* -- device connect -- */
909static int sd_probe(struct usb_interface *intf,
910 const struct usb_device_id *id)
911{
912 PDEBUG(D_PROBE, "camera probe");
913 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd));
914}
915
916static struct usb_driver sd_driver = {
917 .name = MODULE_NAME,
918 .id_table = device_table,
919 .probe = sd_probe,
920 .disconnect = gspca_disconnect,
921};
922
923/* -- module insert / remove -- */
924static int __init sd_mod_init(void)
925{
926 init_pixart_decoder();
927 if (usb_register(&sd_driver) < 0)
928 return -1;
929 PDEBUG(D_PROBE, "v%s registered", version);
930 return 0;
931}
932static void __exit sd_mod_exit(void)
933{
934 usb_deregister(&sd_driver);
935 PDEBUG(D_PROBE, "deregistered");
936}
937
938module_init(sd_mod_init);
939module_exit(sd_mod_exit);