aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/em28xx
diff options
context:
space:
mode:
authorDevin Heitmueller <dheitmueller@kernellabs.com>2009-09-01 00:19:46 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-18 22:47:40 -0400
commitda52a55cff643b8e0b346b9894adf5b93946040d (patch)
tree3cc434722b23e5fcc748de24f37054030ef90e8d /drivers/media/video/em28xx
parent206313db83641022c5ee213ac5f619973a9b427b (diff)
V4L/DVB (12741): em28xx: make video isoc stream work when VBI is enabled
Add code enabling the VBI registers for variants of the em28xx chip that support VBI, and make sure the isoc streaming code continues to work for the video component of the stream (note the video and vbi data arrive intermixed on the same isoc pipe). Note that this version just drops the actual VBI data onto the floor as opposed to processing it. The "#ifdef 0" tags are for the videobuf code that appears in the next patch in this series. We created a separate version of the isoc_copy version for parsing the version of the stream that includes VBI data. In theory, they might be able to be merged at some point in the future, but the initial goal is to ensure that we do not cause any regressions with devices that do not have VBI support. This work was sponsored by EyeMagnet Limited. Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/em28xx')
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c44
-rw-r--r--drivers/media/video/em28xx/em28xx-reg.h4
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c127
-rw-r--r--drivers/media/video/em28xx/em28xx.h7
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;
54module_param(alt, int, 0644); 54module_param(alt, int, 0644);
55MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); 55MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
56 56
57static unsigned int disable_vbi;
58module_param(disable_vbi, int, 0644);
59MODULE_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
655int 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
651int em28xx_set_outfmt(struct em28xx *dev) 669int 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
667static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, 695static 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 */
845static void em28xx_irq_callback(struct urb *urb) 880static 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,
329static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) 329static 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 */
415static 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
640int em28xx_colorlevels_set_default(struct em28xx *dev); 646int em28xx_colorlevels_set_default(struct em28xx *dev);
641int em28xx_capture_start(struct em28xx *dev, int start); 647int em28xx_capture_start(struct em28xx *dev, int start);
648int em28xx_vbi_supported(struct em28xx *dev);
642int em28xx_set_outfmt(struct em28xx *dev); 649int em28xx_set_outfmt(struct em28xx *dev);
643int em28xx_resolution_set(struct em28xx *dev); 650int em28xx_resolution_set(struct em28xx *dev);
644int em28xx_set_alternate(struct em28xx *dev); 651int em28xx_set_alternate(struct em28xx *dev);