Merge branches 'msm-fixes' and 'msm-video' of git://codeaurora.org/quic/kernel/dwalke...
[pandora-kernel.git] / drivers / media / video / uvc / uvc_video.c
index e27cf0d..5555f01 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *      uvc_video.c  --  USB Video Class driver - Video handling
  *
- *      Copyright (C) 2005-2009
- *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *      Copyright (C) 2005-2010
+ *          Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
  *      This program is free software; you can redistribute it and/or modify
  *      it under the terms of the GNU General Public License as published by
@@ -45,6 +45,30 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
                        unit << 8 | intfnum, data, size, timeout);
 }
 
+static const char *uvc_query_name(__u8 query)
+{
+       switch (query) {
+       case UVC_SET_CUR:
+               return "SET_CUR";
+       case UVC_GET_CUR:
+               return "GET_CUR";
+       case UVC_GET_MIN:
+               return "GET_MIN";
+       case UVC_GET_MAX:
+               return "GET_MAX";
+       case UVC_GET_RES:
+               return "GET_RES";
+       case UVC_GET_LEN:
+               return "GET_LEN";
+       case UVC_GET_INFO:
+               return "GET_INFO";
+       case UVC_GET_DEF:
+               return "GET_DEF";
+       default:
+               return "<invalid>";
+       }
+}
+
 int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
                        __u8 intfnum, __u8 cs, void *data, __u16 size)
 {
@@ -53,9 +77,9 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
        ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
                                UVC_CTRL_CONTROL_TIMEOUT);
        if (ret != size) {
-               uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u "
-                       "(unit %u) : %d (exp. %u).\n", query, cs, unit, ret,
-                       size);
+               uvc_printk(KERN_ERR, "Failed to query (%s) UVC control %u on "
+                       "unit %u: %d (exp. %u).\n", uvc_query_name(query), cs,
+                       unit, ret, size);
                return -EIO;
        }
 
@@ -114,6 +138,15 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
                        bandwidth /= 8;
                bandwidth += 12;
 
+               /* The bandwidth estimate is too low for many cameras. Don't use
+                * maximum packet sizes lower than 1024 bytes to try and work
+                * around the problem. According to measurements done on two
+                * different camera models, the value is high enough to get most
+                * resolutions working while not preventing two simultaneous
+                * VGA streams at 15 fps.
+                */
+               bandwidth = max_t(u32, bandwidth, 1024);
+
                ctrl->dwMaxPayloadTransferSize = bandwidth;
        }
 }
@@ -394,6 +427,12 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
 
        fid = data[1] & UVC_STREAM_FID;
 
+       /* Increase the sequence number regardless of any buffer states, so
+        * that discontinuous sequence numbers always indicate lost frames.
+        */
+       if (stream->last_fid != fid)
+               stream->sequence++;
+
        /* Store the payload FID bit and return immediately when the buffer is
         * NULL.
         */
@@ -427,6 +466,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
                else
                        ktime_get_real_ts(&ts);
 
+               buf->buf.sequence = stream->sequence;
                buf->buf.timestamp.tv_sec = ts.tv_sec;
                buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
 
@@ -688,6 +728,7 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
                if (buf->buf.bytesused == stream->queue.buf_used) {
                        stream->queue.buf_used = 0;
                        buf->state = UVC_BUF_STATE_READY;
+                       buf->buf.sequence = ++stream->sequence;
                        uvc_queue_next_buffer(&stream->queue, buf);
                        stream->last_fid ^= UVC_STREAM_FID;
                }
@@ -946,6 +987,7 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
        unsigned int i;
        int ret;
 
+       stream->sequence = -1;
        stream->last_fid = -1;
        stream->bulk.header_size = 0;
        stream->bulk.skip_payload = 0;