diff options
Diffstat (limited to 'drivers/media/video/em28xx')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-core.c | 44 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx-reg.h | 4 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 127 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx.h | 7 |
4 files changed, 173 insertions, 9 deletions
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 98e140b5d95e..d4107f6933f8 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c | |||
@@ -54,6 +54,10 @@ static int alt = EM28XX_PINOUT; | |||
54 | module_param(alt, int, 0644); | 54 | module_param(alt, int, 0644); |
55 | MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); | 55 | MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); |
56 | 56 | ||
57 | static unsigned int disable_vbi; | ||
58 | module_param(disable_vbi, int, 0644); | ||
59 | MODULE_PARM_DESC(disable_vbi, "disable vbi support"); | ||
60 | |||
57 | /* FIXME */ | 61 | /* FIXME */ |
58 | #define em28xx_isocdbg(fmt, arg...) do {\ | 62 | #define em28xx_isocdbg(fmt, arg...) do {\ |
59 | if (core_debug) \ | 63 | if (core_debug) \ |
@@ -648,9 +652,24 @@ int em28xx_capture_start(struct em28xx *dev, int start) | |||
648 | return rc; | 652 | return rc; |
649 | } | 653 | } |
650 | 654 | ||
655 | int em28xx_vbi_supported(struct em28xx *dev) | ||
656 | { | ||
657 | /* Modprobe option to manually disable */ | ||
658 | if (disable_vbi == 1) | ||
659 | return 0; | ||
660 | |||
661 | if (dev->chip_id == CHIP_ID_EM2860 || | ||
662 | dev->chip_id == CHIP_ID_EM2883) | ||
663 | return 1; | ||
664 | |||
665 | /* Version of em28xx that does not support VBI */ | ||
666 | return 0; | ||
667 | } | ||
668 | |||
651 | int em28xx_set_outfmt(struct em28xx *dev) | 669 | int em28xx_set_outfmt(struct em28xx *dev) |
652 | { | 670 | { |
653 | int ret; | 671 | int ret; |
672 | u8 vinctrl; | ||
654 | 673 | ||
655 | ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT, | 674 | ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT, |
656 | dev->format->reg | 0x20, 0xff); | 675 | dev->format->reg | 0x20, 0xff); |
@@ -661,7 +680,16 @@ int em28xx_set_outfmt(struct em28xx *dev) | |||
661 | if (ret < 0) | 680 | if (ret < 0) |
662 | return ret; | 681 | return ret; |
663 | 682 | ||
664 | return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, dev->vinctl); | 683 | vinctrl = dev->vinctl; |
684 | if (em28xx_vbi_supported(dev) == 1) { | ||
685 | vinctrl |= EM28XX_VINCTRL_VBI_RAW; | ||
686 | em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); | ||
687 | em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09); | ||
688 | em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, 0xb4); | ||
689 | em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, 0x0c); | ||
690 | } | ||
691 | |||
692 | return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl); | ||
665 | } | 693 | } |
666 | 694 | ||
667 | static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, | 695 | static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, |
@@ -732,7 +760,14 @@ int em28xx_resolution_set(struct em28xx *dev) | |||
732 | 760 | ||
733 | 761 | ||
734 | em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); | 762 | em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); |
735 | em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2); | 763 | |
764 | /* If we don't set the start position to 4 in VBI mode, we end up | ||
765 | with line 21 being YUYV encoded instead of being in 8-bit | ||
766 | greyscale */ | ||
767 | if (em28xx_vbi_supported(dev) == 1) | ||
768 | em28xx_capture_area_set(dev, 0, 4, width >> 2, height >> 2); | ||
769 | else | ||
770 | em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2); | ||
736 | 771 | ||
737 | return em28xx_scaler_set(dev, dev->hscale, dev->vscale); | 772 | return em28xx_scaler_set(dev, dev->hscale, dev->vscale); |
738 | } | 773 | } |
@@ -844,8 +879,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode); | |||
844 | */ | 879 | */ |
845 | static void em28xx_irq_callback(struct urb *urb) | 880 | static void em28xx_irq_callback(struct urb *urb) |
846 | { | 881 | { |
847 | struct em28xx_dmaqueue *dma_q = urb->context; | 882 | struct em28xx *dev = urb->context; |
848 | struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); | ||
849 | int rc, i; | 883 | int rc, i; |
850 | 884 | ||
851 | switch (urb->status) { | 885 | switch (urb->status) { |
@@ -994,7 +1028,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, | |||
994 | 1028 | ||
995 | usb_fill_int_urb(urb, dev->udev, pipe, | 1029 | usb_fill_int_urb(urb, dev->udev, pipe, |
996 | dev->isoc_ctl.transfer_buffer[i], sb_size, | 1030 | dev->isoc_ctl.transfer_buffer[i], sb_size, |
997 | em28xx_irq_callback, dma_q, 1); | 1031 | em28xx_irq_callback, dev, 1); |
998 | 1032 | ||
999 | urb->number_of_packets = max_packets; | 1033 | urb->number_of_packets = max_packets; |
1000 | urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; | 1034 | urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; |
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h index 3bf69f9ec375..ed12e7ffcbd0 100644 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ b/drivers/media/video/em28xx/em28xx-reg.h | |||
@@ -147,6 +147,10 @@ | |||
147 | #define EM28XX_R31_HSCALEHIGH 0x31 | 147 | #define EM28XX_R31_HSCALEHIGH 0x31 |
148 | #define EM28XX_R32_VSCALELOW 0x32 | 148 | #define EM28XX_R32_VSCALELOW 0x32 |
149 | #define EM28XX_R33_VSCALEHIGH 0x33 | 149 | #define EM28XX_R33_VSCALEHIGH 0x33 |
150 | #define EM28XX_R34_VBI_START_H 0x34 | ||
151 | #define EM28XX_R35_VBI_START_V 0x35 | ||
152 | #define EM28XX_R36_VBI_WIDTH 0x36 | ||
153 | #define EM28XX_R37_VBI_HEIGHT 0x37 | ||
150 | 154 | ||
151 | #define EM28XX_R40_AC97LSB 0x40 | 155 | #define EM28XX_R40_AC97LSB 0x40 |
152 | #define EM28XX_R41_AC97MSB 0x41 | 156 | #define EM28XX_R41_AC97MSB 0x41 |
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index a6bdbc21410e..04c9ecc3c22a 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -329,7 +329,7 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q, | |||
329 | static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) | 329 | static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) |
330 | { | 330 | { |
331 | struct em28xx_buffer *buf; | 331 | struct em28xx_buffer *buf; |
332 | struct em28xx_dmaqueue *dma_q = urb->context; | 332 | struct em28xx_dmaqueue *dma_q = &dev->vidq; |
333 | unsigned char *outp = NULL; | 333 | unsigned char *outp = NULL; |
334 | int i, len = 0, rc = 1; | 334 | int i, len = 0, rc = 1; |
335 | unsigned char *p; | 335 | unsigned char *p; |
@@ -410,6 +410,118 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) | |||
410 | return rc; | 410 | return rc; |
411 | } | 411 | } |
412 | 412 | ||
413 | /* Version of isoc handler that takes into account a mixture of video and | ||
414 | VBI data */ | ||
415 | static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb) | ||
416 | { | ||
417 | struct em28xx_buffer *buf, *vbi_buf; | ||
418 | struct em28xx_dmaqueue *dma_q = &dev->vidq; | ||
419 | unsigned char *outp = NULL; | ||
420 | unsigned char *vbioutp = NULL; | ||
421 | int i, len = 0, rc = 1; | ||
422 | unsigned char *p; | ||
423 | int vbi_size; | ||
424 | |||
425 | if (!dev) | ||
426 | return 0; | ||
427 | |||
428 | if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) | ||
429 | return 0; | ||
430 | |||
431 | if (urb->status < 0) { | ||
432 | print_err_status(dev, -1, urb->status); | ||
433 | if (urb->status == -ENOENT) | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | buf = dev->isoc_ctl.buf; | ||
438 | if (buf != NULL) | ||
439 | outp = videobuf_to_vmalloc(&buf->vb); | ||
440 | for (i = 0; i < urb->number_of_packets; i++) { | ||
441 | int status = urb->iso_frame_desc[i].status; | ||
442 | |||
443 | if (status < 0) { | ||
444 | print_err_status(dev, i, status); | ||
445 | if (urb->iso_frame_desc[i].status != -EPROTO) | ||
446 | continue; | ||
447 | } | ||
448 | |||
449 | len = urb->iso_frame_desc[i].actual_length - 4; | ||
450 | |||
451 | if (urb->iso_frame_desc[i].actual_length <= 0) { | ||
452 | /* em28xx_isocdbg("packet %d is empty",i); - spammy */ | ||
453 | continue; | ||
454 | } | ||
455 | if (urb->iso_frame_desc[i].actual_length > | ||
456 | dev->max_pkt_size) { | ||
457 | em28xx_isocdbg("packet bigger than packet size"); | ||
458 | continue; | ||
459 | } | ||
460 | |||
461 | p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; | ||
462 | |||
463 | /* capture type 0 = vbi start | ||
464 | capture type 1 = video start | ||
465 | capture type 2 = video in progress */ | ||
466 | if (p[0] == 0x33 && p[1] == 0x95) { | ||
467 | dev->capture_type = 0; | ||
468 | dev->vbi_read = 0; | ||
469 | em28xx_isocdbg("VBI START HEADER!!!\n"); | ||
470 | dev->cur_field = p[2]; | ||
471 | } | ||
472 | |||
473 | /* FIXME: get rid of hard-coded value */ | ||
474 | vbi_size = 720 * 0x0c; | ||
475 | |||
476 | if (dev->capture_type == 0) { | ||
477 | if (dev->vbi_read >= vbi_size) { | ||
478 | /* We've already read all the VBI data, so | ||
479 | treat the rest as video */ | ||
480 | printk("djh c should never happen\n"); | ||
481 | } else if ((dev->vbi_read + len) < vbi_size) { | ||
482 | /* This entire frame is VBI data */ | ||
483 | dev->vbi_read += len; | ||
484 | } else { | ||
485 | /* Some of this frame is VBI data and some is | ||
486 | video data */ | ||
487 | int vbi_data_len = vbi_size - dev->vbi_read; | ||
488 | dev->vbi_read += vbi_data_len; | ||
489 | dev->capture_type = 1; | ||
490 | p += vbi_data_len; | ||
491 | len -= vbi_data_len; | ||
492 | } | ||
493 | } | ||
494 | |||
495 | if (dev->capture_type == 1) { | ||
496 | dev->capture_type = 2; | ||
497 | em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2], | ||
498 | len, (p[2] & 1) ? "odd" : "even"); | ||
499 | |||
500 | if (dev->progressive || !(dev->cur_field & 1)) { | ||
501 | if (buf != NULL) | ||
502 | buffer_filled(dev, dma_q, buf); | ||
503 | get_next_buf(dma_q, &buf); | ||
504 | if (buf == NULL) | ||
505 | outp = NULL; | ||
506 | else | ||
507 | outp = videobuf_to_vmalloc(&buf->vb); | ||
508 | } | ||
509 | if (buf != NULL) { | ||
510 | if (dev->cur_field & 1) | ||
511 | buf->top_field = 0; | ||
512 | else | ||
513 | buf->top_field = 1; | ||
514 | } | ||
515 | |||
516 | dma_q->pos = 0; | ||
517 | } | ||
518 | if (buf != NULL && dev->capture_type == 2) | ||
519 | em28xx_copy_video(dev, dma_q, buf, p, outp, len); | ||
520 | } | ||
521 | return rc; | ||
522 | } | ||
523 | |||
524 | |||
413 | /* ------------------------------------------------------------------ | 525 | /* ------------------------------------------------------------------ |
414 | Videobuf operations | 526 | Videobuf operations |
415 | ------------------------------------------------------------------*/ | 527 | ------------------------------------------------------------------*/ |
@@ -494,9 +606,16 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, | |||
494 | urb_init = 1; | 606 | urb_init = 1; |
495 | 607 | ||
496 | if (urb_init) { | 608 | if (urb_init) { |
497 | rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, | 609 | if (em28xx_vbi_supported(dev) == 1) |
498 | EM28XX_NUM_BUFS, dev->max_pkt_size, | 610 | rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, |
499 | em28xx_isoc_copy); | 611 | EM28XX_NUM_BUFS, |
612 | dev->max_pkt_size, | ||
613 | em28xx_isoc_copy_vbi); | ||
614 | else | ||
615 | rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, | ||
616 | EM28XX_NUM_BUFS, | ||
617 | dev->max_pkt_size, | ||
618 | em28xx_isoc_copy); | ||
500 | if (rc < 0) | 619 | if (rc < 0) |
501 | goto fail; | 620 | goto fail; |
502 | } | 621 | } |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 0f2ba9a40d17..1656d2cf34a9 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -544,6 +544,12 @@ struct em28xx { | |||
544 | enum em28xx_dev_state state; | 544 | enum em28xx_dev_state state; |
545 | enum em28xx_io_method io; | 545 | enum em28xx_io_method io; |
546 | 546 | ||
547 | /* vbi related state tracking */ | ||
548 | int capture_type; | ||
549 | int vbi_read; | ||
550 | unsigned char cur_field; | ||
551 | |||
552 | |||
547 | struct work_struct request_module_wk; | 553 | struct work_struct request_module_wk; |
548 | 554 | ||
549 | /* locks */ | 555 | /* locks */ |
@@ -639,6 +645,7 @@ int em28xx_audio_setup(struct em28xx *dev); | |||
639 | 645 | ||
640 | int em28xx_colorlevels_set_default(struct em28xx *dev); | 646 | int em28xx_colorlevels_set_default(struct em28xx *dev); |
641 | int em28xx_capture_start(struct em28xx *dev, int start); | 647 | int em28xx_capture_start(struct em28xx *dev, int start); |
648 | int em28xx_vbi_supported(struct em28xx *dev); | ||
642 | int em28xx_set_outfmt(struct em28xx *dev); | 649 | int em28xx_set_outfmt(struct em28xx *dev); |
643 | int em28xx_resolution_set(struct em28xx *dev); | 650 | int em28xx_resolution_set(struct em28xx *dev); |
644 | int em28xx_set_alternate(struct em28xx *dev); | 651 | int em28xx_set_alternate(struct em28xx *dev); |