aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/uvc
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2009-12-09 20:57:48 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-02-26 13:10:24 -0500
commit310fe52461e6244b01a04b011c2e886d6b69de16 (patch)
treee75b1f25bbf77747d49f183f618ffa4831d4846b /drivers/media/video/uvc
parent0f7ff39532f1d2328e54b65ce5022c71f06e44d6 (diff)
V4L/DVB (13827): uvcvideo: Switch to a monotonic clock for V4L2 buffers timestamps
The realtime clock provided by do_gettimeofday() is affected by time jumps caused by NTP or DST. Furthermore, preliminary investigation showed that SMP systems the realtime clock is based on the CPU TSC, and those could get slightly out of sync, resulting in jitter in the timestamps depending on which processor handles the USB interrupts. Instead of the realtime clock, use a monotonic high resolution clock to timestamp the buffer. As this could in theory introduce a regression with some userspace applications expecting a realtime clock timestamp, add a module parameter to switch back to the realtime clock. Thanks to Paulo Assis for pointing out and investigating the issue. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/uvc')
-rw-r--r--drivers/media/video/uvc/uvc_driver.c49
-rw-r--r--drivers/media/video/uvc/uvc_queue.c1
-rw-r--r--drivers/media/video/uvc/uvc_video.c10
-rw-r--r--drivers/media/video/uvc/uvcvideo.h1
4 files changed, 51 insertions, 10 deletions
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 391cccca7ffc..05ac2774d3b9 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -43,6 +43,7 @@
43#define DRIVER_VERSION "v0.1.0" 43#define DRIVER_VERSION "v0.1.0"
44#endif 44#endif
45 45
46unsigned int uvc_clock_param = CLOCK_MONOTONIC;
46unsigned int uvc_no_drop_param; 47unsigned int uvc_no_drop_param;
47static unsigned int uvc_quirks_param; 48static unsigned int uvc_quirks_param;
48unsigned int uvc_trace_param; 49unsigned int uvc_trace_param;
@@ -1892,6 +1893,45 @@ static int uvc_reset_resume(struct usb_interface *intf)
1892} 1893}
1893 1894
1894/* ------------------------------------------------------------------------ 1895/* ------------------------------------------------------------------------
1896 * Module parameters
1897 */
1898
1899static int uvc_clock_param_get(char *buffer, struct kernel_param *kp)
1900{
1901 if (uvc_clock_param == CLOCK_MONOTONIC)
1902 return sprintf(buffer, "CLOCK_MONOTONIC");
1903 else
1904 return sprintf(buffer, "CLOCK_REALTIME");
1905}
1906
1907static int uvc_clock_param_set(const char *val, struct kernel_param *kp)
1908{
1909 if (strncasecmp(val, "clock_", strlen("clock_")) == 0)
1910 val += strlen("clock_");
1911
1912 if (strcasecmp(val, "monotonic") == 0)
1913 uvc_clock_param = CLOCK_MONOTONIC;
1914 else if (strcasecmp(val, "realtime") == 0)
1915 uvc_clock_param = CLOCK_REALTIME;
1916 else
1917 return -EINVAL;
1918
1919 return 0;
1920}
1921
1922module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get,
1923 &uvc_clock_param, S_IRUGO|S_IWUSR);
1924MODULE_PARM_DESC(clock, "Video buffers timestamp clock");
1925module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
1926MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
1927module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
1928MODULE_PARM_DESC(quirks, "Forced device quirks");
1929module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
1930MODULE_PARM_DESC(trace, "Trace level bitmask");
1931module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
1932MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
1933
1934/* ------------------------------------------------------------------------
1895 * Driver initialization and cleanup 1935 * Driver initialization and cleanup
1896 */ 1936 */
1897 1937
@@ -2197,15 +2237,6 @@ static void __exit uvc_cleanup(void)
2197module_init(uvc_init); 2237module_init(uvc_init);
2198module_exit(uvc_cleanup); 2238module_exit(uvc_cleanup);
2199 2239
2200module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
2201MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
2202module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
2203MODULE_PARM_DESC(quirks, "Forced device quirks");
2204module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
2205MODULE_PARM_DESC(trace, "Trace level bitmask");
2206module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
2207MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
2208
2209MODULE_AUTHOR(DRIVER_AUTHOR); 2240MODULE_AUTHOR(DRIVER_AUTHOR);
2210MODULE_DESCRIPTION(DRIVER_DESC); 2241MODULE_DESCRIPTION(DRIVER_DESC);
2211MODULE_LICENSE("GPL"); 2242MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index ea11839cba4a..4a925a31b0e0 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -502,7 +502,6 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
502 spin_unlock_irqrestore(&queue->irqlock, flags); 502 spin_unlock_irqrestore(&queue->irqlock, flags);
503 503
504 buf->buf.sequence = queue->sequence++; 504 buf->buf.sequence = queue->sequence++;
505 do_gettimeofday(&buf->buf.timestamp);
506 505
507 wake_up(&buf->wait); 506 wake_up(&buf->wait);
508 return nextbuf; 507 return nextbuf;
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 7dcf534a0cf3..6b0666be370f 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -410,6 +410,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
410 * when the EOF bit is set to force synchronisation on the next packet. 410 * when the EOF bit is set to force synchronisation on the next packet.
411 */ 411 */
412 if (buf->state != UVC_BUF_STATE_ACTIVE) { 412 if (buf->state != UVC_BUF_STATE_ACTIVE) {
413 struct timespec ts;
414
413 if (fid == stream->last_fid) { 415 if (fid == stream->last_fid) {
414 uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of " 416 uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
415 "sync).\n"); 417 "sync).\n");
@@ -419,6 +421,14 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
419 return -ENODATA; 421 return -ENODATA;
420 } 422 }
421 423
424 if (uvc_clock_param == CLOCK_MONOTONIC)
425 ktime_get_ts(&ts);
426 else
427 ktime_get_real_ts(&ts);
428
429 buf->buf.timestamp.tv_sec = ts.tv_sec;
430 buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
431
422 /* TODO: Handle PTS and SCR. */ 432 /* TODO: Handle PTS and SCR. */
423 buf->state = UVC_BUF_STATE_ACTIVE; 433 buf->state = UVC_BUF_STATE_ACTIVE;
424 } 434 }
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 2337585001ea..adcba31008be 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -533,6 +533,7 @@ struct uvc_driver {
533#define UVC_WARN_MINMAX 0 533#define UVC_WARN_MINMAX 0
534#define UVC_WARN_PROBE_DEF 1 534#define UVC_WARN_PROBE_DEF 1
535 535
536extern unsigned int uvc_clock_param;
536extern unsigned int uvc_no_drop_param; 537extern unsigned int uvc_no_drop_param;
537extern unsigned int uvc_trace_param; 538extern unsigned int uvc_trace_param;
538extern unsigned int uvc_timeout_param; 539extern unsigned int uvc_timeout_param;