[RFC 1/2] uvc: Add a quirk flag for cameras that do not produce correct timestamps

Sakari Ailus
2014-11-05T16:14:10Z

The UVC devices do produce hardware timestamps according to the spec, but
not all cameras implement it or implement it correctly. Add a quirk flag for
such devices, and use monotonic timestamp from the end of the frame instead.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
drivers/media/usb/uvc/uvc_queue.c | 6 ++++--
drivers/media/usb/uvc/uvc_video.c | 14 +++++++++++++-
drivers/media/usb/uvc/uvcvideo.h | 4 +++-
3 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index 6e92d20..3f6432f 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -141,7 +141,7 @@ static struct vb2_ops uvc_queue_qops = {
};

int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
- int drop_corrupted)
+ bool drop_corrupted, bool tstamp_eof)
{
int ret;

@@ -152,7 +152,9 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
queue->queue.ops = &uvc_queue_qops;
queue->queue.mem_ops = &vb2_vmalloc_memops;
queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
- | V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
+ | (tstamp_eof ? V4L2_BUF_FLAG_TSTAMP_SRC_EOF
+ : V4L2_BUF_FLAG_TSTAMP_SRC_SOE);
+
ret = vb2_queue_init(&queue->queue);
if (ret)
return ret;
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index df81b9c..f599112 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -382,6 +382,9 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
u16 host_sof;
u16 dev_sof;

+ if (stream->dev->quirks & UVC_QUIRK_BAD_TIMESTAMP)
+ return;
+
switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
case UVC_STREAM_PTS | UVC_STREAM_SCR:
header_size = 12;
@@ -490,6 +493,9 @@ static int uvc_video_clock_init(struct uvc_streaming *stream)
{
struct uvc_clock *clock = &stream->clock;

+ if (stream->dev->quirks & UVC_QUIRK_BAD_TIMESTAMP)
+ return 0;
+
spin_lock_init(&clock->lock);
clock->size = 32;

@@ -615,6 +621,11 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
u32 rem;
u64 y;

+ if (stream->dev->quirks & UVC_QUIRK_BAD_TIMESTAMP) {
+ v4l2_get_timestamp(&v4l2_buf->timestamp);
+ return;
+ }
+
spin_lock_irqsave(&clock->lock, flags);

if (clock->count < clock->size)
@@ -1779,7 +1790,8 @@ int uvc_video_init(struct uvc_streaming *stream)
atomic_set(&stream->active, 0);

/* Initialize the video buffers queue. */
- ret = uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param);
+ ret = uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param,
+ stream->dev->quirks & UVC_QUIRK_BAD_TIMESTAMP);
if (ret)
return ret;

diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 864ada7..89a638c 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -148,6 +148,7 @@
#define UVC_QUIRK_PROBE_DEF 0x00000100
#define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200
#define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400
+#define UVC_QUIRK_BAD_TIMESTAMP 0x00000800

/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
@@ -622,7 +623,8 @@ extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);

/* Video buffers queue management. */
extern int uvc_queue_init(struct uvc_video_queue *queue,
- enum v4l2_buf_type type, int drop_corrupted);
+ enum v4l2_buf_type type, bool drop_corrupted,
+ bool tstamp_eof);
extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
struct v4l2_requestbuffers *rb);
extern void uvc_free_buffers(struct uvc_video_queue *queue);
--
2.1.0.231.g7484e3b