]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/media/video/uvc/uvc_video.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6-omap-h63xx.git] / drivers / media / video / uvc / uvc_video.c
index 9bc4705be78d8ebb893a9dd24d2e6215c344507f..a95e17329c5bb366d6eb7d70039a3328e8dbbc77 100644 (file)
@@ -61,7 +61,7 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
        return 0;
 }
 
-static void uvc_fixup_buffer_size(struct uvc_video_device *video,
+static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
        struct uvc_streaming_control *ctrl)
 {
        struct uvc_format *format;
@@ -84,6 +84,31 @@ static void uvc_fixup_buffer_size(struct uvc_video_device *video,
              video->dev->uvc_version < 0x0110))
                ctrl->dwMaxVideoFrameSize =
                        frame->dwMaxVideoFrameBufferSize;
+
+       if (video->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
+           video->streaming->intf->num_altsetting > 1) {
+               u32 interval;
+               u32 bandwidth;
+
+               interval = (ctrl->dwFrameInterval > 100000)
+                        ? ctrl->dwFrameInterval
+                        : frame->dwFrameInterval[0];
+
+               /* Compute a bandwidth estimation by multiplying the frame
+                * size by the number of video frames per second, divide the
+                * result by the number of USB frames (or micro-frames for
+                * high-speed devices) per second and add the UVC header size
+                * (assumed to be 12 bytes long).
+                */
+               bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
+               bandwidth *= 10000000 / interval + 1;
+               bandwidth /= 1000;
+               if (video->dev->udev->speed == USB_SPEED_HIGH)
+                       bandwidth /= 8;
+               bandwidth += 12;
+
+               ctrl->dwMaxPayloadTransferSize = bandwidth;
+       }
 }
 
 static int uvc_get_video_ctrl(struct uvc_video_device *video,
@@ -158,10 +183,11 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
                ctrl->bMaxVersion = 0;
        }
 
-       /* Some broken devices return a null or wrong dwMaxVideoFrameSize.
-        * Try to get the value from the format and frame descriptors.
+       /* Some broken devices return null or wrong dwMaxVideoFrameSize and
+        * dwMaxPayloadTransferSize fields. Try to get the value from the
+        * format and frame descriptors.
         */
-       uvc_fixup_buffer_size(video, ctrl);
+       uvc_fixup_video_ctrl(video, ctrl);
        ret = 0;
 
 out:
@@ -540,6 +566,9 @@ static void uvc_video_decode_bulk(struct urb *urb,
        u8 *mem;
        int len, ret;
 
+       if (urb->actual_length == 0)
+               return;
+
        mem = urb->transfer_buffer;
        len = urb->actual_length;
        video->bulk.payload_size += len;
@@ -699,27 +728,47 @@ static void uvc_free_urb_buffers(struct uvc_video_device *video)
  * already allocated when resuming from suspend, in which case it will
  * return without touching the buffers.
  *
- * Return 0 on success or -ENOMEM when out of memory.
+ * Limit the buffer size to UVC_MAX_PACKETS bulk/isochronous packets. If the
+ * system is too low on memory try successively smaller numbers of packets
+ * until allocation succeeds.
+ *
+ * Return the number of allocated packets on success or 0 when out of memory.
  */
 static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
-       unsigned int size)
+       unsigned int size, unsigned int psize, gfp_t gfp_flags)
 {
+       unsigned int npackets;
        unsigned int i;
 
        /* Buffers are already allocated, bail out. */
        if (video->urb_size)
                return 0;
 
-       for (i = 0; i < UVC_URBS; ++i) {
-               video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
-                       size, GFP_KERNEL, &video->urb_dma[i]);
-               if (video->urb_buffer[i] == NULL) {
-                       uvc_free_urb_buffers(video);
-                       return -ENOMEM;
+       /* Compute the number of packets. Bulk endpoints might transfer UVC
+        * payloads accross multiple URBs.
+        */
+       npackets = DIV_ROUND_UP(size, psize);
+       if (npackets > UVC_MAX_PACKETS)
+               npackets = UVC_MAX_PACKETS;
+
+       /* Retry allocations until one succeed. */
+       for (; npackets > 1; npackets /= 2) {
+               for (i = 0; i < UVC_URBS; ++i) {
+                       video->urb_buffer[i] = usb_buffer_alloc(
+                               video->dev->udev, psize * npackets,
+                               gfp_flags | __GFP_NOWARN, &video->urb_dma[i]);
+                       if (!video->urb_buffer[i]) {
+                               uvc_free_urb_buffers(video);
+                               break;
+                       }
+               }
+
+               if (i == UVC_URBS) {
+                       video->urb_size = psize * npackets;
+                       return npackets;
                }
        }
 
-       video->urb_size = size;
        return 0;
 }
 
@@ -753,29 +802,19 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
 {
        struct urb *urb;
        unsigned int npackets, i, j;
-       __u16 psize;
-       __u32 size;
+       u16 psize;
+       u32 size;
 
-       /* Compute the number of isochronous packets to allocate by dividing
-        * the maximum video frame size by the packet size. Limit the result
-        * to UVC_MAX_ISO_PACKETS.
-        */
        psize = le16_to_cpu(ep->desc.wMaxPacketSize);
        psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
-
        size = video->streaming->ctrl.dwMaxVideoFrameSize;
-       if (size > UVC_MAX_FRAME_SIZE)
-               return -EINVAL;
 
-       npackets = DIV_ROUND_UP(size, psize);
-       if (npackets > UVC_MAX_ISO_PACKETS)
-               npackets = UVC_MAX_ISO_PACKETS;
+       npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags);
+       if (npackets == 0)
+               return -ENOMEM;
 
        size = npackets * psize;
 
-       if (uvc_alloc_urb_buffers(video, size) < 0)
-               return -ENOMEM;
-
        for (i = 0; i < UVC_URBS; ++i) {
                urb = usb_alloc_urb(npackets, gfp_flags);
                if (urb == NULL) {
@@ -814,25 +853,20 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
        struct usb_host_endpoint *ep, gfp_t gfp_flags)
 {
        struct urb *urb;
-       unsigned int pipe, i;
-       __u16 psize;
-       __u32 size;
-
-       /* Compute the bulk URB size. Some devices set the maximum payload
-        * size to a value too high for memory-constrained devices. We must
-        * then transfer the payload accross multiple URBs. To be consistant
-        * with isochronous mode, allocate maximum UVC_MAX_ISO_PACKETS per bulk
-        * URB.
-        */
+       unsigned int npackets, pipe, i;
+       u16 psize;
+       u32 size;
+
        psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
        size = video->streaming->ctrl.dwMaxPayloadTransferSize;
        video->bulk.max_payload_size = size;
-       if (size > psize * UVC_MAX_ISO_PACKETS)
-               size = psize * UVC_MAX_ISO_PACKETS;
 
-       if (uvc_alloc_urb_buffers(video, size) < 0)
+       npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags);
+       if (npackets == 0)
                return -ENOMEM;
 
+       size = npackets * psize;
+
        if (usb_endpoint_dir_in(&ep->desc))
                pipe = usb_rcvbulkpipe(video->dev->udev,
                                       ep->desc.bEndpointAddress);
@@ -1021,11 +1055,20 @@ int uvc_video_init(struct uvc_video_device *video)
         */
        usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
 
-       /* Some webcams don't suport GET_DEF requests on the probe control. We
-        * fall back to GET_CUR if GET_DEF fails.
+       /* Set the streaming probe control with default streaming parameters
+        * retrieved from the device. Webcams that don't suport GET_DEF
+        * requests on the probe control will just keep their current streaming
+        * parameters.
+        */
+       if (uvc_get_video_ctrl(video, probe, 1, GET_DEF) == 0)
+               uvc_set_video_ctrl(video, probe, 1);
+
+       /* Initialize the streaming parameters with the probe control current
+        * value. This makes sure SET_CUR requests on the streaming commit
+        * control will always use values retrieved from a successful GET_CUR
+        * request on the probe control, as required by the UVC specification.
         */
-       if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_DEF)) < 0 &&
-           (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+       if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
                return ret;
 
        /* Check if the default format descriptor exists. Use the first