Commit a4837015 authored by Frank Schaefer's avatar Frank Schaefer Committed by Mauro Carvalho Chehab

[media] em28xx: refactor VBI data processing code in em28xx_urb_data_copy()

When a new frame header is detected in em28xx_urb_data_copy() and the data
packet contains both, VBI data and video data, the prevoius VBI buffer doesn't
get finished and is overwritten with the new VBI data.
This bug is not triggered with isochronous USB transfers, because the data
packetes are much smaller than the VBI data size.
But when using USB bulk transfers, the whole data of an URB is treated as
single packet, which is usually much larger then the VBI data size.
Refactor the VBI data processing code to fix this bug, but also to simplify the
code and make it similar to the video data processing code part (which allows
further code abstraction/unification in the future).
The changes have been tested with device "Hauppauge HVR-900".
Signed-off-by: default avatarFrank Schäfer <fschaefer.oss@googlemail.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 8732533b
...@@ -418,8 +418,9 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb) ...@@ -418,8 +418,9 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
} }
/* capture type 0 = vbi start /* capture type 0 = vbi start
capture type 1 = video start capture type 1 = vbi in progress
capture type 2 = video in progress */ capture type 2 = video start
capture type 3 = video in progress */
len = actual_length; len = actual_length;
if (len >= 4) { if (len >= 4) {
/* NOTE: headers are always 4 bytes and /* NOTE: headers are always 4 bytes and
...@@ -438,7 +439,7 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb) ...@@ -438,7 +439,7 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
len -= 4; len -= 4;
} else if (p[0] == 0x22 && p[1] == 0x5a) { } else if (p[0] == 0x22 && p[1] == 0x5a) {
/* start video */ /* start video */
dev->capture_type = 1; dev->capture_type = 2;
dev->top_field = !(p[2] & 1); dev->top_field = !(p[2] & 1);
p += 4; p += 4;
len -= 4; len -= 4;
...@@ -448,51 +449,45 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb) ...@@ -448,51 +449,45 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
* have no continuation header */ * have no continuation header */
if (dev->capture_type == 0) { if (dev->capture_type == 0) {
dev->capture_type = 1;
if (dev->top_field) { /* Brand new frame */
if (vbi_buf != NULL)
finish_buffer(dev, vbi_buf);
vbi_buf = get_next_buf(dev, vbi_dma_q);
dev->usb_ctl.vbi_buf = vbi_buf;
if (vbi_buf == NULL)
vbioutp = NULL;
else
vbioutp =
videobuf_to_vmalloc(&vbi_buf->vb);
}
if (vbi_buf != NULL) {
vbi_buf->top_field = dev->top_field;
vbi_buf->pos = 0;
}
}
if (dev->capture_type == 1) {
int vbi_size = dev->vbi_width * dev->vbi_height; int vbi_size = dev->vbi_width * dev->vbi_height;
if (dev->vbi_read >= vbi_size) { int vbi_data_len = ((dev->vbi_read + len) > vbi_size) ?
/* We've already read all the VBI data, so (vbi_size - dev->vbi_read) : len;
treat the rest as video */
em28xx_isocdbg("dev->vbi_read > vbi_size\n"); /* Copy VBI data */
} else if ((dev->vbi_read + len) < vbi_size) { if (vbi_buf != NULL)
/* This entire frame is VBI data */
if (dev->vbi_read == 0 && dev->top_field) {
/* Brand new frame */
if (vbi_buf != NULL)
finish_buffer(dev, vbi_buf);
vbi_buf = get_next_buf(dev, vbi_dma_q);
dev->usb_ctl.vbi_buf = vbi_buf;
if (vbi_buf == NULL)
vbioutp = NULL;
else
vbioutp = videobuf_to_vmalloc(
&vbi_buf->vb);
}
if (dev->vbi_read == 0) {
if (vbi_buf != NULL) {
vbi_buf->top_field
= dev->top_field;
vbi_buf->pos = 0;
}
}
dev->vbi_read += len;
em28xx_copy_vbi(dev, vbi_buf, p, vbioutp, len);
} else {
/* Some of this frame is VBI data and some is
video data */
int vbi_data_len = vbi_size - dev->vbi_read;
dev->vbi_read += vbi_data_len;
em28xx_copy_vbi(dev, vbi_buf, p, vbioutp, em28xx_copy_vbi(dev, vbi_buf, p, vbioutp,
vbi_data_len); vbi_data_len);
dev->capture_type = 1; dev->vbi_read += vbi_data_len;
if (vbi_data_len < len) {
/* Continue with copying video data */
dev->capture_type = 2;
p += vbi_data_len; p += vbi_data_len;
len -= vbi_data_len; len -= vbi_data_len;
} }
} }
if (dev->capture_type == 1) { if (dev->capture_type == 2) {
dev->capture_type = 2; dev->capture_type = 3;
if (dev->progressive || dev->top_field) { if (dev->progressive || dev->top_field) {
if (buf != NULL) if (buf != NULL)
finish_buffer(dev, buf); finish_buffer(dev, buf);
...@@ -509,7 +504,7 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb) ...@@ -509,7 +504,7 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
} }
} }
if (buf != NULL && dev->capture_type == 2 && len > 0) if (buf != NULL && dev->capture_type == 3 && len > 0)
em28xx_copy_video(dev, buf, p, outp, len); em28xx_copy_video(dev, buf, p, outp, len);
} }
return rc; return rc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment