diff options
author | Devin Heitmueller <dheitmueller@kernellabs.com> | 2009-09-01 00:19:46 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-18 22:47:40 -0400 |
commit | da52a55cff643b8e0b346b9894adf5b93946040d (patch) | |
tree | 3cc434722b23e5fcc748de24f37054030ef90e8d /drivers/media/video/em28xx/em28xx-video.c | |
parent | 206313db83641022c5ee213ac5f619973a9b427b (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/em28xx-video.c')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 127 |
1 files changed, 123 insertions, 4 deletions
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 | } |