diff options
Diffstat (limited to 'drivers/media/video/gspca/tv8532.c')
-rw-r--r-- | drivers/media/video/gspca/tv8532.c | 142 |
1 files changed, 34 insertions, 108 deletions
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c index 968a5911704f..94163cceb28a 100644 --- a/drivers/media/video/gspca/tv8532.c +++ b/drivers/media/video/gspca/tv8532.c | |||
@@ -30,15 +30,10 @@ MODULE_LICENSE("GPL"); | |||
30 | struct sd { | 30 | struct sd { |
31 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 31 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
32 | 32 | ||
33 | int buflen; /* current length of tmpbuf */ | 33 | __u16 brightness; |
34 | __u8 tmpbuf[352 * 288 + 10 * 288]; /* no protection... */ | 34 | __u16 contrast; |
35 | __u8 tmpbuf2[352 * 288]; /* no protection... */ | ||
36 | 35 | ||
37 | unsigned short brightness; | 36 | __u8 packet; |
38 | unsigned short contrast; | ||
39 | |||
40 | char packet; | ||
41 | char synchro; | ||
42 | }; | 37 | }; |
43 | 38 | ||
44 | /* V4L2 controls supported by the driver */ | 39 | /* V4L2 controls supported by the driver */ |
@@ -78,7 +73,7 @@ static struct ctrl sd_ctrls[] = { | |||
78 | }, | 73 | }, |
79 | }; | 74 | }; |
80 | 75 | ||
81 | static struct v4l2_pix_format sif_mode[] = { | 76 | static const struct v4l2_pix_format sif_mode[] = { |
82 | {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | 77 | {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, |
83 | .bytesperline = 176, | 78 | .bytesperline = 176, |
84 | .sizeimage = 176 * 144, | 79 | .sizeimage = 176 * 144, |
@@ -392,6 +387,8 @@ static void setbrightness(struct gspca_dev *gspca_dev) | |||
392 | /* -- start the camera -- */ | 387 | /* -- start the camera -- */ |
393 | static int sd_start(struct gspca_dev *gspca_dev) | 388 | static int sd_start(struct gspca_dev *gspca_dev) |
394 | { | 389 | { |
390 | struct sd *sd = (struct sd *) gspca_dev; | ||
391 | |||
395 | reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32); | 392 | reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32); |
396 | reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00); | 393 | reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00); |
397 | tv_8532ReadRegisters(gspca_dev); | 394 | tv_8532ReadRegisters(gspca_dev); |
@@ -443,6 +440,10 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
443 | /************************************************/ | 440 | /************************************************/ |
444 | tv_8532_PollReg(gspca_dev); | 441 | tv_8532_PollReg(gspca_dev); |
445 | reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */ | 442 | reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */ |
443 | |||
444 | gspca_dev->empty_packet = 0; /* check the empty packets */ | ||
445 | sd->packet = 0; /* ignore the first packets */ | ||
446 | |||
446 | return 0; | 447 | return 0; |
447 | } | 448 | } |
448 | 449 | ||
@@ -451,111 +452,36 @@ static void sd_stopN(struct gspca_dev *gspca_dev) | |||
451 | reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); | 452 | reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); |
452 | } | 453 | } |
453 | 454 | ||
454 | static void tv8532_preprocess(struct gspca_dev *gspca_dev) | ||
455 | { | ||
456 | struct sd *sd = (struct sd *) gspca_dev; | ||
457 | /* we should received a whole frame with header and EOL marker | ||
458 | * in gspca_dev->tmpbuf and return a GBRG pattern in gspca_dev->tmpbuf2 | ||
459 | * sequence 2bytes header the Alternate pixels bayer GB 4 bytes | ||
460 | * Alternate pixels bayer RG 4 bytes EOL */ | ||
461 | int width = gspca_dev->width; | ||
462 | int height = gspca_dev->height; | ||
463 | unsigned char *dst = sd->tmpbuf2; | ||
464 | unsigned char *data = sd->tmpbuf; | ||
465 | int i; | ||
466 | |||
467 | /* precompute where is the good bayer line */ | ||
468 | if (((data[3] + data[width + 7]) >> 1) | ||
469 | + (data[4] >> 2) | ||
470 | + (data[width + 6] >> 1) >= ((data[2] + data[width + 6]) >> 1) | ||
471 | + (data[3] >> 2) | ||
472 | + (data[width + 5] >> 1)) | ||
473 | data += 3; | ||
474 | else | ||
475 | data += 2; | ||
476 | for (i = 0; i < height / 2; i++) { | ||
477 | memcpy(dst, data, width); | ||
478 | data += width + 3; | ||
479 | dst += width; | ||
480 | memcpy(dst, data, width); | ||
481 | data += width + 7; | ||
482 | dst += width; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | 455 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, |
487 | struct gspca_frame *frame, /* target */ | 456 | struct gspca_frame *frame, /* target */ |
488 | __u8 *data, /* isoc packet */ | 457 | __u8 *data, /* isoc packet */ |
489 | int len) /* iso packet length */ | 458 | int len) /* iso packet length */ |
490 | { | 459 | { |
491 | struct sd *sd = (struct sd *) gspca_dev; | 460 | struct sd *sd = (struct sd *) gspca_dev; |
492 | 461 | int packet_type0, packet_type1; | |
493 | if (data[0] != 0x80) { | 462 | |
494 | sd->packet++; | 463 | packet_type0 = packet_type1 = INTER_PACKET; |
495 | if (sd->buflen + len > sizeof sd->tmpbuf) { | 464 | if (gspca_dev->empty_packet) { |
496 | if (gspca_dev->last_packet_type != DISCARD_PACKET) { | 465 | gspca_dev->empty_packet = 0; |
497 | PDEBUG(D_PACK, "buffer overflow"); | 466 | sd->packet = gspca_dev->height / 2; |
498 | gspca_dev->last_packet_type = DISCARD_PACKET; | 467 | packet_type0 = FIRST_PACKET; |
499 | } | 468 | } else if (sd->packet == 0) |
500 | return; | 469 | return; /* 2 more lines in 352x288 ! */ |
501 | } | 470 | sd->packet--; |
502 | memcpy(&sd->tmpbuf[sd->buflen], data, len); | 471 | if (sd->packet == 0) |
503 | sd->buflen += len; | 472 | packet_type1 = LAST_PACKET; |
504 | return; | 473 | |
505 | } | 474 | /* each packet contains: |
506 | 475 | * - header 2 bytes | |
507 | /* here we detect 0x80 */ | 476 | * - RG line |
508 | /* counter is limited so we need few header for a frame :) */ | 477 | * - 4 bytes |
509 | 478 | * - GB line | |
510 | /* header 0x80 0x80 0x80 0x80 0x80 */ | 479 | * - 4 bytes |
511 | /* packet 00 63 127 145 00 */ | 480 | */ |
512 | /* sof 0 1 1 0 0 */ | 481 | gspca_frame_add(gspca_dev, packet_type0, |
513 | 482 | frame, data + 2, gspca_dev->width); | |
514 | /* update sequence */ | 483 | gspca_frame_add(gspca_dev, packet_type1, |
515 | if (sd->packet == 63 || sd->packet == 127) | 484 | frame, data + gspca_dev->width + 6, gspca_dev->width); |
516 | sd->synchro = 1; | ||
517 | |||
518 | /* is there a frame start ? */ | ||
519 | if (sd->packet >= (gspca_dev->height >> 1) - 1) { | ||
520 | PDEBUG(D_PACK, "SOF > %d packet %d", sd->synchro, | ||
521 | sd->packet); | ||
522 | if (!sd->synchro) { /* start of frame */ | ||
523 | if (gspca_dev->last_packet_type == FIRST_PACKET) { | ||
524 | tv8532_preprocess(gspca_dev); | ||
525 | frame = gspca_frame_add(gspca_dev, | ||
526 | LAST_PACKET, | ||
527 | frame, sd->tmpbuf2, | ||
528 | gspca_dev->width * | ||
529 | gspca_dev->width); | ||
530 | } | ||
531 | gspca_frame_add(gspca_dev, FIRST_PACKET, | ||
532 | frame, data, 0); | ||
533 | memcpy(sd->tmpbuf, data, len); | ||
534 | sd->buflen = len; | ||
535 | sd->packet = 0; | ||
536 | return; | ||
537 | } | ||
538 | if (gspca_dev->last_packet_type != DISCARD_PACKET) { | ||
539 | PDEBUG(D_PACK, | ||
540 | "Warning wrong TV8532 frame detection %d", | ||
541 | sd->packet); | ||
542 | gspca_dev->last_packet_type = DISCARD_PACKET; | ||
543 | } | ||
544 | return; | ||
545 | } | ||
546 | |||
547 | if (!sd->synchro) { | ||
548 | /* Drop packet frame corrupt */ | ||
549 | PDEBUG(D_PACK, "DROP SOF %d packet %d", | ||
550 | sd->synchro, sd->packet); | ||
551 | sd->packet = 0; | ||
552 | gspca_dev->last_packet_type = DISCARD_PACKET; | ||
553 | return; | ||
554 | } | ||
555 | sd->synchro = 1; | ||
556 | sd->packet++; | ||
557 | memcpy(&sd->tmpbuf[sd->buflen], data, len); | ||
558 | sd->buflen += len; | ||
559 | } | 485 | } |
560 | 486 | ||
561 | static void setcontrast(struct gspca_dev *gspca_dev) | 487 | static void setcontrast(struct gspca_dev *gspca_dev) |