aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/media/usb/uvc/uvc_video.c22
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h1
2 files changed, 23 insertions, 0 deletions
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 5df8f61d39cd..aebcf9b25a16 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -471,8 +471,29 @@ static void uvc_video_clock_add_sample(struct uvc_clock *clock,
{
unsigned long flags;
+ /*
+ * If we write new data on the position where we had the last
+ * overflow, remove the overflow pointer. There is no SOF overflow
+ * in the whole circular buffer.
+ */
+ if (clock->head == clock->last_sof_overflow)
+ clock->last_sof_overflow = -1;
+
spin_lock_irqsave(&clock->lock, flags);
+ if (clock->count > 0 && clock->last_sof > sample->dev_sof) {
+ /*
+ * Remove data from the circular buffer that is older than the
+ * last SOF overflow. We only support one SOF overflow per
+ * circular buffer.
+ */
+ if (clock->last_sof_overflow != -1)
+ clock->count = (clock->head - clock->last_sof_overflow
+ + clock->size) % clock->size;
+ clock->last_sof_overflow = clock->head;
+ }
+
+ /* Add sample. */
clock->samples[clock->head] = *sample;
clock->head = (clock->head + 1) % clock->size;
clock->count = min(clock->count + 1, clock->size);
@@ -616,6 +637,7 @@ static void uvc_video_clock_reset(struct uvc_clock *clock)
clock->head = 0;
clock->count = 0;
clock->last_sof = -1;
+ clock->last_sof_overflow = -1;
clock->sof_offset = -1;
}
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index e5b12717016f..f21207debd54 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -501,6 +501,7 @@ struct uvc_streaming {
unsigned int head;
unsigned int count;
unsigned int size;
+ unsigned int last_sof_overflow;
u16 last_sof;
u16 sof_offset;