aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca
diff options
context:
space:
mode:
authorHans de Goede <j.w.r.degoede@hhs.nl>2008-09-03 16:12:14 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-09-03 17:37:24 -0400
commit327c4abf74a4426676df6c359b2a3dea2a5d126e (patch)
tree005359b56ee32e6dc645b57d0f0da518292719a8 /drivers/media/video/gspca
parent62ee8eeebd1bf6c29977800ac18dfcecf584d42e (diff)
V4L/DVB (8812): gspca: Do pac73xx webcams work.
- documentation for some registers - some preparations for adding autogain_n_exposure functionality - various pac7311 fixes - disable brightness and colors controls for 7311 - fix contrast control for 7311 - add hflip and vflip controls for 7311 - minimal jpeg header - proper SOF detection Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl> Signed-off-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/gspca')
-rw-r--r--drivers/media/video/gspca/pac207.c36
-rw-r--r--drivers/media/video/gspca/pac7311.c309
-rw-r--r--drivers/media/video/gspca/pac_common.h53
3 files changed, 220 insertions, 178 deletions
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index d9668f4cb4d1..620c9631629e 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -181,9 +181,6 @@ static const __u8 pac207_sensor_init[][8] = {
181 /* 48 reg_72 Rate Control end BalSize_4a =0x36 */ 181 /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
182static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 }; 182static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
183 183
184static const unsigned char pac207_sof_marker[5] =
185 { 0xff, 0xff, 0x00, 0xff, 0x96 };
186
187static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, 184static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
188 const u8 *buffer, u16 length) 185 const u8 *buffer, u16 length)
189{ 186{
@@ -367,31 +364,8 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
367 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES; 364 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
368} 365}
369 366
370static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev, 367/* Include pac common sof detection functions */
371 unsigned char *m, int len) 368#include "pac_common.h"
372{
373 struct sd *sd = (struct sd *) gspca_dev;
374 int i;
375
376 /* Search for the SOF marker (fixed part) in the header */
377 for (i = 0; i < len; i++) {
378 if (m[i] == pac207_sof_marker[sd->sof_read]) {
379 sd->sof_read++;
380 if (sd->sof_read == sizeof(pac207_sof_marker)) {
381 PDEBUG(D_STREAM,
382 "SOF found, bytes to analyze: %u."
383 " Frame starts at byte #%u",
384 len, i + 1);
385 sd->sof_read = 0;
386 return m + i + 1;
387 }
388 } else {
389 sd->sof_read = 0;
390 }
391 }
392
393 return NULL;
394}
395 369
396static void sd_pkt_scan(struct gspca_dev *gspca_dev, 370static void sd_pkt_scan(struct gspca_dev *gspca_dev,
397 struct gspca_frame *frame, 371 struct gspca_frame *frame,
@@ -401,14 +375,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
401 struct sd *sd = (struct sd *) gspca_dev; 375 struct sd *sd = (struct sd *) gspca_dev;
402 unsigned char *sof; 376 unsigned char *sof;
403 377
404 sof = pac207_find_sof(gspca_dev, data, len); 378 sof = pac_find_sof(gspca_dev, data, len);
405 if (sof) { 379 if (sof) {
406 int n; 380 int n;
407 381
408 /* finish decoding current frame */ 382 /* finish decoding current frame */
409 n = sof - data; 383 n = sof - data;
410 if (n > sizeof pac207_sof_marker) 384 if (n > sizeof pac_sof_marker)
411 n -= sizeof pac207_sof_marker; 385 n -= sizeof pac_sof_marker;
412 else 386 else
413 n = 0; 387 n = 0;
414 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, 388 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 4cc9379ee411..bed04cc9a584 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -19,10 +19,36 @@
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21 21
22/* Some documentation about various registers as determined by trial and error.
23 When the register addresses differ between the 7202 and the 7311 the 2
24 different addresses are written as 7302addr/7311addr, when one of the 2
25 addresses is a - sign that register description is not valid for the
26 matching IC.
27
28 Register page 1:
29
30 Address Description
31 -/0x08 Unknown compressor related, must always be 8 except when not
32 in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
33 -/0x1b Auto white balance related, bit 0 is AWB enable (inverted)
34 bits 345 seem to toggle per color gains on/off (inverted)
35 0x78 Global control, bit 6 controls the LED (inverted)
36 -/0x80 JPEG compression ratio ? Best not touched
37
38 Register page 3/4:
39
40 Address Description
41 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
42 the 7302, so one of 3, 6, 9, ...
43 -/0x0f Master gain 1-245, low value = high gain
44 0x10/- Master gain 0-31
45 -/0x10 Another gain 0-15, limited influence (1-2x gain I guess)
46 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
47*/
48
22#define MODULE_NAME "pac7311" 49#define MODULE_NAME "pac7311"
23 50
24#include "gspca.h" 51#include "gspca.h"
25#include "jpeg.h"
26 52
27MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); 53MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
28MODULE_DESCRIPTION("Pixart PAC7311"); 54MODULE_DESCRIPTION("Pixart PAC7311");
@@ -32,25 +58,22 @@ MODULE_LICENSE("GPL");
32struct sd { 58struct sd {
33 struct gspca_dev gspca_dev; /* !! must be the first item */ 59 struct gspca_dev gspca_dev; /* !! must be the first item */
34 60
35 int lum_sum;
36 atomic_t avg_lum;
37 atomic_t do_gain;
38
39 unsigned char brightness; 61 unsigned char brightness;
40 unsigned char contrast; 62 unsigned char contrast;
41 unsigned char colors; 63 unsigned char colors;
42 unsigned char autogain; 64 unsigned char autogain;
43 __u8 hflip; 65 __u8 hflip;
44 __u8 vflip; 66 __u8 vflip;
45 __u8 qindex;
46
47 char tosof; /* number of bytes before next start of frame */
48 signed char ag_cnt;
49#define AG_CNT_START 13
50 67
51 __u8 sensor; 68 __u8 sensor;
52#define SENSOR_PAC7302 0 69#define SENSOR_PAC7302 0
53#define SENSOR_PAC7311 1 70#define SENSOR_PAC7311 1
71
72 u8 sof_read;
73 u8 header_read;
74 u8 autogain_ignore_frames;
75
76 atomic_t avg_lum;
54}; 77};
55 78
56/* V4L2 controls supported by the driver */ 79/* V4L2 controls supported by the driver */
@@ -92,7 +115,7 @@ static struct ctrl sd_ctrls[] = {
92#define CONTRAST_MAX 255 115#define CONTRAST_MAX 255
93 .maximum = CONTRAST_MAX, 116 .maximum = CONTRAST_MAX,
94 .step = 1, 117 .step = 1,
95#define CONTRAST_DEF 60 118#define CONTRAST_DEF 127
96 .default_value = CONTRAST_DEF, 119 .default_value = CONTRAST_DEF,
97 }, 120 },
98 .set = sd_setcontrast, 121 .set = sd_setcontrast,
@@ -243,7 +266,7 @@ static const __u8 start_7302[] = {
243 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22, 266 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
244 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44, 267 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
245 0x6e, 1, 0x08, 268 0x6e, 1, 0x08,
246 0xff, 1, 0x03, /* page 1 */ 269 0xff, 1, 0x01, /* page 1 */
247 0x78, 1, 0x00, 270 0x78, 1, 0x00,
248 0, 0 /* end of sequence */ 271 0, 0 /* end of sequence */
249}; 272};
@@ -274,9 +297,9 @@ static const __u8 page3_7302[] = {
274 297
275/* pac 7311 */ 298/* pac 7311 */
276static const __u8 probe_7311[] = { 299static const __u8 probe_7311[] = {
277 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */ 300 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
278 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */ 301 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
279 0x78, 0x44, /* Bit_0=start stream, Bit_7=LED */ 302 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
280 0xff, 0x04, 303 0xff, 0x04,
281 0x27, 0x80, 304 0x27, 0x80,
282 0x28, 0xca, 305 0x28, 0xca,
@@ -340,18 +363,6 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
340 500); 363 500);
341} 364}
342 365
343static __u8 reg_r(struct gspca_dev *gspca_dev,
344 __u8 index)
345{
346 usb_control_msg(gspca_dev->dev,
347 usb_rcvctrlpipe(gspca_dev->dev, 0),
348 0, /* request */
349 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
350 0, /* value */
351 index, gspca_dev->usb_buf, 1,
352 500);
353 return gspca_dev->usb_buf[0];
354}
355 366
356static void reg_w(struct gspca_dev *gspca_dev, 367static void reg_w(struct gspca_dev *gspca_dev,
357 __u8 index, 368 __u8 index,
@@ -413,7 +424,7 @@ static void reg_w_var(struct gspca_dev *gspca_dev,
413 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302); 424 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
414 break; 425 break;
415 default: 426 default:
416 if (len > 32) { 427 if (len > 64) {
417 PDEBUG(D_ERR|D_STREAM, 428 PDEBUG(D_ERR|D_STREAM,
418 "Incorrect variable sequence"); 429 "Incorrect variable sequence");
419 return; 430 return;
@@ -453,7 +464,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
453 cam->nmodes = 1; 464 cam->nmodes = 1;
454 } else { 465 } else {
455 PDEBUG(D_CONF, "Find Sensor PAC7311"); 466 PDEBUG(D_CONF, "Find Sensor PAC7311");
456 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302); 467 reg_w_seq(gspca_dev, probe_7311, sizeof probe_7311);
457 468
458 cam->cam_mode = vga_mode; 469 cam->cam_mode = vga_mode;
459 cam->nmodes = ARRAY_SIZE(vga_mode); 470 cam->nmodes = ARRAY_SIZE(vga_mode);
@@ -465,8 +476,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
465 sd->autogain = AUTOGAIN_DEF; 476 sd->autogain = AUTOGAIN_DEF;
466 sd->hflip = HFLIP_DEF; 477 sd->hflip = HFLIP_DEF;
467 sd->vflip = VFLIP_DEF; 478 sd->vflip = VFLIP_DEF;
468 sd->qindex = 3;
469 sd->ag_cnt = -1;
470 return 0; 479 return 0;
471} 480}
472 481
@@ -497,6 +506,7 @@ static void setbrightcont(struct gspca_dev *gspca_dev)
497 reg_w(gspca_dev, 0xdc, 0x01); 506 reg_w(gspca_dev, 0xdc, 0x01);
498} 507}
499 508
509/* This function is used by pac7302 only */
500static void setbrightness(struct gspca_dev *gspca_dev) 510static void setbrightness(struct gspca_dev *gspca_dev)
501{ 511{
502 struct sd *sd = (struct sd *) gspca_dev; 512 struct sd *sd = (struct sd *) gspca_dev;
@@ -506,7 +516,10 @@ static void setbrightness(struct gspca_dev *gspca_dev)
506 setbrightcont(gspca_dev); 516 setbrightcont(gspca_dev);
507 return; 517 return;
508 } 518 }
509/*jfm: inverted?*/ 519/* HDG: this is not brightness but gain, I'll add gain and exposure controls
520 in a next patch */
521 return;
522
510 brightness = BRIGHTNESS_MAX - sd->brightness; 523 brightness = BRIGHTNESS_MAX - sd->brightness;
511 reg_w(gspca_dev, 0xff, 0x04); 524 reg_w(gspca_dev, 0xff, 0x04);
512 reg_w(gspca_dev, 0x0e, 0x00); 525 reg_w(gspca_dev, 0x0e, 0x00);
@@ -524,12 +537,13 @@ static void setcontrast(struct gspca_dev *gspca_dev)
524 setbrightcont(gspca_dev); 537 setbrightcont(gspca_dev);
525 return; 538 return;
526 } 539 }
527 reg_w(gspca_dev, 0xff, 0x01); 540 reg_w(gspca_dev, 0xff, 0x04);
528 reg_w(gspca_dev, 0x10, sd->contrast); 541 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
529 /* load registers to sensor (Bit 0, auto clear) */ 542 /* load registers to sensor (Bit 0, auto clear) */
530 reg_w(gspca_dev, 0x11, 0x01); 543 reg_w(gspca_dev, 0x11, 0x01);
531} 544}
532 545
546/* This function is used by pac7302 only */
533static void setcolors(struct gspca_dev *gspca_dev) 547static void setcolors(struct gspca_dev *gspca_dev)
534{ 548{
535 struct sd *sd = (struct sd *) gspca_dev; 549 struct sd *sd = (struct sd *) gspca_dev;
@@ -551,36 +565,24 @@ static void setcolors(struct gspca_dev *gspca_dev)
551 reg_w(gspca_dev, 0x0f + 2 * i + 1, v); 565 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
552 } 566 }
553 reg_w(gspca_dev, 0xdc, 0x01); 567 reg_w(gspca_dev, 0xdc, 0x01);
554 return; 568 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
555 } 569 }
556 reg_w(gspca_dev, 0xff, 0x01);
557 reg_w(gspca_dev, 0x80, sd->colors);
558 /* load registers to sensor (Bit 0, auto clear) */
559 reg_w(gspca_dev, 0x11, 0x01);
560 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
561} 570}
562 571
563static void setautogain(struct gspca_dev *gspca_dev)
564{
565 struct sd *sd = (struct sd *) gspca_dev;
566
567 if (sd->autogain) {
568 sd->lum_sum = 0;
569 sd->ag_cnt = AG_CNT_START;
570 } else {
571 sd->ag_cnt = -1;
572 }
573}
574
575/* this function is used by pac7302 only */
576static void sethvflip(struct gspca_dev *gspca_dev) 572static void sethvflip(struct gspca_dev *gspca_dev)
577{ 573{
578 struct sd *sd = (struct sd *) gspca_dev; 574 struct sd *sd = (struct sd *) gspca_dev;
579 __u8 data; 575 __u8 data;
580 576
581 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ 577 if (sd->sensor == SENSOR_PAC7302) {
582 data = (sd->hflip ? 0x00 : 0x08) 578 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
583 | (sd->vflip ? 0x04 : 0x00); 579 data = (sd->hflip ? 0x00 : 0x08)
580 | (sd->vflip ? 0x04 : 0x00);
581 } else {
582 reg_w(gspca_dev, 0xff, 0x04); /* page 3 */
583 data = (sd->hflip ? 0x04 : 0x00)
584 | (sd->vflip ? 0x08 : 0x00);
585 }
584 reg_w(gspca_dev, 0x21, data); 586 reg_w(gspca_dev, 0x21, data);
585 reg_w(gspca_dev, 0x11, 0x01); 587 reg_w(gspca_dev, 0x11, 0x01);
586} 588}
@@ -588,7 +590,6 @@ static void sethvflip(struct gspca_dev *gspca_dev)
588/* this function is called at open time */ 590/* this function is called at open time */
589static int sd_open(struct gspca_dev *gspca_dev) 591static int sd_open(struct gspca_dev *gspca_dev)
590{ 592{
591 reg_w(gspca_dev, 0x78, 0x44); /* Turn on LED */
592 return 0; 593 return 0;
593} 594}
594 595
@@ -596,7 +597,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
596{ 597{
597 struct sd *sd = (struct sd *) gspca_dev; 598 struct sd *sd = (struct sd *) gspca_dev;
598 599
599 sd->tosof = 0; 600 sd->sof_read = 0;
600 601
601 if (sd->sensor == SENSOR_PAC7302) 602 if (sd->sensor == SENSOR_PAC7302)
602 reg_w_var(gspca_dev, start_7302); 603 reg_w_var(gspca_dev, start_7302);
@@ -606,7 +607,6 @@ static void sd_start(struct gspca_dev *gspca_dev)
606 setcontrast(gspca_dev); 607 setcontrast(gspca_dev);
607 setbrightness(gspca_dev); 608 setbrightness(gspca_dev);
608 setcolors(gspca_dev); 609 setcolors(gspca_dev);
609 setautogain(gspca_dev);
610 610
611 /* set correct resolution */ 611 /* set correct resolution */
612 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { 612 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
@@ -621,7 +621,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
621 break; 621 break;
622 case 1: /* 320x240 pac7311 */ 622 case 1: /* 320x240 pac7311 */
623 reg_w(gspca_dev, 0xff, 0x04); 623 reg_w(gspca_dev, 0xff, 0x04);
624 reg_w(gspca_dev, 0x02, 0x07); 624 reg_w(gspca_dev, 0x02, 0x03);
625 reg_w(gspca_dev, 0xff, 0x01); 625 reg_w(gspca_dev, 0xff, 0x01);
626 reg_w(gspca_dev, 0x08, 0x09); 626 reg_w(gspca_dev, 0x08, 0x09);
627 reg_w(gspca_dev, 0x17, 0x30); 627 reg_w(gspca_dev, 0x17, 0x30);
@@ -650,6 +650,10 @@ static void sd_start(struct gspca_dev *gspca_dev)
650 reg_w(gspca_dev, 0x78, 0x44); 650 reg_w(gspca_dev, 0x78, 0x44);
651 reg_w(gspca_dev, 0x78, 0x45); 651 reg_w(gspca_dev, 0x78, 0x45);
652 } 652 }
653
654 sd->sof_read = 0;
655 sd->autogain_ignore_frames = 0;
656 atomic_set(&sd->avg_lum, -1);
653} 657}
654 658
655static void sd_stopN(struct gspca_dev *gspca_dev) 659static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -657,6 +661,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
657 struct sd *sd = (struct sd *) gspca_dev; 661 struct sd *sd = (struct sd *) gspca_dev;
658 662
659 if (sd->sensor == SENSOR_PAC7302) { 663 if (sd->sensor == SENSOR_PAC7302) {
664 reg_w(gspca_dev, 0xff, 0x01);
660 reg_w(gspca_dev, 0x78, 0x00); 665 reg_w(gspca_dev, 0x78, 0x00);
661 reg_w(gspca_dev, 0x78, 0x00); 666 reg_w(gspca_dev, 0x78, 0x00);
662 return; 667 return;
@@ -668,9 +673,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
668 reg_w(gspca_dev, 0x2a, 0x0e); 673 reg_w(gspca_dev, 0x2a, 0x0e);
669 reg_w(gspca_dev, 0xff, 0x01); 674 reg_w(gspca_dev, 0xff, 0x01);
670 reg_w(gspca_dev, 0x3e, 0x20); 675 reg_w(gspca_dev, 0x3e, 0x20);
671 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ 676 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
672 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ 677 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
673 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ 678 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
674} 679}
675 680
676static void sd_stop0(struct gspca_dev *gspca_dev) 681static void sd_stop0(struct gspca_dev *gspca_dev)
@@ -690,42 +695,22 @@ static void sd_close(struct gspca_dev *gspca_dev)
690 695
691static void do_autogain(struct gspca_dev *gspca_dev) 696static void do_autogain(struct gspca_dev *gspca_dev)
692{ 697{
693 struct sd *sd = (struct sd *) gspca_dev;
694 int luma;
695 int luma_mean = 128;
696 int luma_delta = 20;
697 __u8 spring = 5;
698 int Gbright;
699
700 if (!atomic_read(&sd->do_gain))
701 return;
702 atomic_set(&sd->do_gain, 0);
703
704 luma = atomic_read(&sd->avg_lum);
705 Gbright = reg_r(gspca_dev, 0x02);
706 PDEBUG(D_FRAM, "luma mean %d", luma);
707 if (luma < luma_mean - luma_delta ||
708 luma > luma_mean + luma_delta) {
709 Gbright += (luma_mean - luma) >> spring;
710 if (Gbright > 0x1a)
711 Gbright = 0x1a;
712 else if (Gbright < 4)
713 Gbright = 4;
714 PDEBUG(D_FRAM, "gbright %d", Gbright);
715 if (sd->sensor == SENSOR_PAC7302) {
716 reg_w(gspca_dev, 0xff, 0x03);
717 reg_w(gspca_dev, 0x10, Gbright);
718 /* load registers to sensor (Bit 0, auto clear) */
719 reg_w(gspca_dev, 0x11, 0x01);
720 } else {
721 reg_w(gspca_dev, 0xff, 0x04);
722 reg_w(gspca_dev, 0x0f, Gbright);
723 /* load registers to sensor (Bit 0, auto clear) */
724 reg_w(gspca_dev, 0x11, 0x01);
725 }
726 }
727} 698}
728 699
700static const unsigned char pac7311_jpeg_header1[] = {
701 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08
702};
703
704static const unsigned char pac7311_jpeg_header2[] = {
705 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,
706 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
707};
708
709/* Include pac common sof detection functions */
710#include "pac_common.h"
711
712#define HEADER_LENGTH 2
713
729/* this function is run at interrupt level */ 714/* this function is run at interrupt level */
730static void sd_pkt_scan(struct gspca_dev *gspca_dev, 715static void sd_pkt_scan(struct gspca_dev *gspca_dev,
731 struct gspca_frame *frame, /* target */ 716 struct gspca_frame *frame, /* target */
@@ -733,58 +718,89 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
733 int len) /* iso packet length */ 718 int len) /* iso packet length */
734{ 719{
735 struct sd *sd = (struct sd *) gspca_dev; 720 struct sd *sd = (struct sd *) gspca_dev;
736 int i; 721 unsigned char *sof;
737 722
738#define INTER_FRAME 0x53 /* eof + inter frame + sof */ 723 sof = pac_find_sof(gspca_dev, data, len);
739#define LUM_OFFSET 0x1e /* reverse offset / start of frame */ 724 if (sof) {
740 725 unsigned char tmpbuf[4];
741 /* 726 int n, lum_offset, footer_length;
742 * inside a frame, there may be: 727
743 * escaped ff ('ff 00') 728 if (sd->sensor == SENSOR_PAC7302) {
744 * sequences'ff ff ff xx' to remove 729 lum_offset = 34 + sizeof pac_sof_marker;
745 * end of frame ('ff d9') 730 footer_length = 74;
746 * at the end of frame, there are: 731 } else {
747 * ff d9 end of frame 732 lum_offset = 24 + sizeof pac_sof_marker;
748 * 0x33 bytes 733 footer_length = 26;
749 * one byte luminosity 734 }
750 * 0x16 bytes 735
751 * ff ff 00 ff 96 62 44 start of frame 736 /* Finish decoding current frame */
752 */ 737 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
753 738 if (n < 0) {
754 if (sd->tosof != 0) { /* if outside a frame */ 739 frame->data_end += n;
755 740 n = 0;
756 /* get the luminosity and go to the start of frame */ 741 }
757 data += sd->tosof; 742 frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
758 len -= sd->tosof; 743 data, n);
759 if (sd->tosof > LUM_OFFSET) 744 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
760 sd->lum_sum += data[-LUM_OFFSET]; 745 frame->data_end[-2] == 0xff &&
761 sd->tosof = 0; 746 frame->data_end[-1] == 0xd9)
762 jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21); 747 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
748 NULL, 0);
749
750 n = sof - data;
751 len -= n;
752 data = sof;
753
754 /* Get average lumination */
755 if (gspca_dev->last_packet_type == LAST_PACKET &&
756 n >= lum_offset) {
757 if (sd->sensor == SENSOR_PAC7302)
758 atomic_set(&sd->avg_lum,
759 (data[-lum_offset] << 8) |
760 data[-lum_offset + 1]);
761 else
762 atomic_set(&sd->avg_lum,
763 data[-lum_offset] +
764 data[-lum_offset + 1]);
765 } else {
766 atomic_set(&sd->avg_lum, -1);
767 }
768
769 /* Start the new frame with the jpeg header */
770 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
771 pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
772 if (sd->sensor == SENSOR_PAC7302) {
773 /* The PAC7302 has the image rotated 90 degrees */
774 tmpbuf[0] = gspca_dev->width >> 8;
775 tmpbuf[1] = gspca_dev->width & 0xff;
776 tmpbuf[2] = gspca_dev->height >> 8;
777 tmpbuf[3] = gspca_dev->height & 0xff;
778 } else {
779 tmpbuf[0] = gspca_dev->height >> 8;
780 tmpbuf[1] = gspca_dev->height & 0xff;
781 tmpbuf[2] = gspca_dev->width >> 8;
782 tmpbuf[3] = gspca_dev->width & 0xff;
783 }
784 gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
785 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
786 pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
787
788 sd->header_read = 0;
763 } 789 }
764 790
765 for (i = 0; i < len; i++) { 791 if (sd->header_read < HEADER_LENGTH) {
766 if (data[i] != 0xff) 792 /* skip the variable part of the sof header */
767 continue; 793 int needed = HEADER_LENGTH - sd->header_read;
768 switch (data[i + 1]) { 794 if (len <= needed) {
769 case 0xd9: /* 'ff d9' end of frame */ 795 sd->header_read += len;
770 frame = gspca_frame_add(gspca_dev, 796 return;
771 LAST_PACKET,
772 frame, data, i + 2);
773 data += i + INTER_FRAME;
774 len -= i + INTER_FRAME;
775 i = 0;
776 if (len > -LUM_OFFSET)
777 sd->lum_sum += data[-LUM_OFFSET];
778 if (len < 0) {
779 sd->tosof = -len;
780 break;
781 }
782 jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
783 break;
784 } 797 }
798 data += needed;
799 len -= needed;
800 sd->header_read = HEADER_LENGTH;
785 } 801 }
786 gspca_frame_add(gspca_dev, INTER_PACKET, 802
787 frame, data, i); 803 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
788} 804}
789 805
790static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) 806static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -846,8 +862,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
846 struct sd *sd = (struct sd *) gspca_dev; 862 struct sd *sd = (struct sd *) gspca_dev;
847 863
848 sd->autogain = val; 864 sd->autogain = val;
849 if (gspca_dev->streaming) 865
850 setautogain(gspca_dev);
851 return 0; 866 return 0;
852} 867}
853 868
diff --git a/drivers/media/video/gspca/pac_common.h b/drivers/media/video/gspca/pac_common.h
new file mode 100644
index 000000000000..a19b5d44c009
--- /dev/null
+++ b/drivers/media/video/gspca/pac_common.h
@@ -0,0 +1,53 @@
1/*
2 * Pixart PAC207BCA / PAC73xx common functions
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
26static const unsigned char pac_sof_marker[5] =
27 { 0xff, 0xff, 0x00, 0xff, 0x96 };
28
29static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev,
30 unsigned char *m, int len)
31{
32 struct sd *sd = (struct sd *) gspca_dev;
33 int i;
34
35 /* Search for the SOF marker (fixed part) in the header */
36 for (i = 0; i < len; i++) {
37 if (m[i] == pac_sof_marker[sd->sof_read]) {
38 sd->sof_read++;
39 if (sd->sof_read == sizeof(pac_sof_marker)) {
40 PDEBUG(D_STREAM,
41 "SOF found, bytes to analyze: %u."
42 " Frame starts at byte #%u",
43 len, i + 1);
44 sd->sof_read = 0;
45 return m + i + 1;
46 }
47 } else {
48 sd->sof_read = 0;
49 }
50 }
51
52 return NULL;
53}