diff options
author | Hans de Goede <j.w.r.degoede@hhs.nl> | 2008-09-03 16:12:14 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-09-03 17:37:24 -0400 |
commit | 327c4abf74a4426676df6c359b2a3dea2a5d126e (patch) | |
tree | 005359b56ee32e6dc645b57d0f0da518292719a8 /drivers/media/video/gspca | |
parent | 62ee8eeebd1bf6c29977800ac18dfcecf584d42e (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.c | 36 | ||||
-rw-r--r-- | drivers/media/video/gspca/pac7311.c | 309 | ||||
-rw-r--r-- | drivers/media/video/gspca/pac_common.h | 53 |
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 */ |
182 | static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 }; | 182 | static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 }; |
183 | 183 | ||
184 | static const unsigned char pac207_sof_marker[5] = | ||
185 | { 0xff, 0xff, 0x00, 0xff, 0x96 }; | ||
186 | |||
187 | static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, | 184 | static 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 | ||
370 | static 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 | ||
396 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | 370 | static 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 | ||
27 | MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); | 53 | MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); |
28 | MODULE_DESCRIPTION("Pixart PAC7311"); | 54 | MODULE_DESCRIPTION("Pixart PAC7311"); |
@@ -32,25 +58,22 @@ MODULE_LICENSE("GPL"); | |||
32 | struct sd { | 58 | struct 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 */ |
276 | static const __u8 probe_7311[] = { | 299 | static 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 | ||
343 | static __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 | ||
356 | static void reg_w(struct gspca_dev *gspca_dev, | 367 | static 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 */ | ||
500 | static void setbrightness(struct gspca_dev *gspca_dev) | 510 | static 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 */ | ||
533 | static void setcolors(struct gspca_dev *gspca_dev) | 547 | static 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 | ||
563 | static 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 */ | ||
576 | static void sethvflip(struct gspca_dev *gspca_dev) | 572 | static 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 */ |
589 | static int sd_open(struct gspca_dev *gspca_dev) | 591 | static 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 | ||
655 | static void sd_stopN(struct gspca_dev *gspca_dev) | 659 | static 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 | ||
676 | static void sd_stop0(struct gspca_dev *gspca_dev) | 681 | static void sd_stop0(struct gspca_dev *gspca_dev) |
@@ -690,42 +695,22 @@ static void sd_close(struct gspca_dev *gspca_dev) | |||
690 | 695 | ||
691 | static void do_autogain(struct gspca_dev *gspca_dev) | 696 | static 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 | ||
700 | static const unsigned char pac7311_jpeg_header1[] = { | ||
701 | 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08 | ||
702 | }; | ||
703 | |||
704 | static 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 */ |
730 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | 715 | static 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 | ||
790 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) | 806 | static 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 | |||
26 | static const unsigned char pac_sof_marker[5] = | ||
27 | { 0xff, 0xff, 0x00, 0xff, 0x96 }; | ||
28 | |||
29 | static 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 | } | ||