The patch number 8209 was added via Mauro Carvalho Chehab <[EMAIL PROTECTED]>
to http://linuxtv.org/hg/v4l-dvb master development tree.

Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel

If anyone has any objections, please let us know by sending a message to:
        [EMAIL PROTECTED]

------

From: Laurent Pinchart  <[EMAIL PROTECTED]>
uvcvideo: Don't free URB buffers on suspend.


All submitted URBs must be killed at suspend time, but URB buffers don't have
to be freed. Avoiding a free on suspend/reallocate on resume lowers the presure
on system memory.

Signed-off-by: Laurent Pinchart <[EMAIL PROTECTED]>
Signed-off-by: Mauro Carvalho Chehab <[EMAIL PROTECTED]>


---

 linux/drivers/media/video/uvc/uvc_video.c |   96 ++++++++++++++--------
 linux/drivers/media/video/uvc/uvcvideo.h  |    2 
 2 files changed, 66 insertions(+), 32 deletions(-)

diff -r 07c29bcc1199 -r 0276304b76b9 linux/drivers/media/video/uvc/uvc_video.c
--- a/linux/drivers/media/video/uvc/uvc_video.c Fri Jul 04 00:35:26 2008 +0000
+++ b/linux/drivers/media/video/uvc/uvc_video.c Fri Jul 04 00:36:21 2008 +0000
@@ -554,9 +554,56 @@ static void uvc_video_complete(struct ur
 }
 
 /*
+ * Free transfer buffers.
+ */
+static void uvc_free_urb_buffers(struct uvc_video_device *video)
+{
+       unsigned int i;
+
+       for (i = 0; i < UVC_URBS; ++i) {
+               if (video->urb_buffer[i]) {
+                       usb_buffer_free(video->dev->udev, video->urb_size,
+                               video->urb_buffer[i], video->urb_dma[i]);
+                       video->urb_buffer[i] = NULL;
+               }
+       }
+
+       video->urb_size = 0;
+}
+
+/*
+ * Allocate transfer buffers. This function can be called with buffers
+ * 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.
+ */
+static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
+       unsigned int size)
+{
+       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;
+               }
+       }
+
+       video->urb_size = size;
+       return 0;
+}
+
+/*
  * Uninitialize isochronous/bulk URBs and free transfer buffers.
  */
-static void uvc_uninit_video(struct uvc_video_device *video)
+static void uvc_uninit_video(struct uvc_video_device *video, int free_buffers)
 {
        struct urb *urb;
        unsigned int i;
@@ -566,19 +613,12 @@ static void uvc_uninit_video(struct uvc_
                        continue;
 
                usb_kill_urb(urb);
-               /* urb->transfer_buffer_length is not touched by USB core, so
-                * we can use it here as the buffer length.
-                */
-               if (video->urb_buffer[i]) {
-                       usb_buffer_free(video->dev->udev,
-                               urb->transfer_buffer_length,
-                               video->urb_buffer[i], urb->transfer_dma);
-                       video->urb_buffer[i] = NULL;
-               }
-
                usb_free_urb(urb);
                video->urb[i] = NULL;
        }
+
+       if (free_buffers)
+               uvc_free_urb_buffers(video);
 }
 
 /*
@@ -610,18 +650,13 @@ static int uvc_init_video_isoc(struct uv
 
        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) {
-                       uvc_uninit_video(video);
-                       return -ENOMEM;
-               }
-
-               video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
-                       size, gfp_flags, &urb->transfer_dma);
-               if (video->urb_buffer[i] == NULL) {
-                       usb_free_urb(urb);
-                       uvc_uninit_video(video);
+                       uvc_uninit_video(video, 1);
                        return -ENOMEM;
                }
 
@@ -632,6 +667,7 @@ static int uvc_init_video_isoc(struct uv
                urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
                urb->interval = ep->desc.bInterval;
                urb->transfer_buffer = video->urb_buffer[i];
+               urb->transfer_dma = video->urb_dma[i];
                urb->complete = uvc_video_complete;
                urb->number_of_packets = npackets;
                urb->transfer_buffer_length = size;
@@ -671,20 +707,15 @@ static int uvc_init_video_bulk(struct uv
        if (size > psize * UVC_MAX_ISO_PACKETS)
                size = psize * UVC_MAX_ISO_PACKETS;
 
+       if (uvc_alloc_urb_buffers(video, size) < 0)
+               return -ENOMEM;
+
        pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress);
 
        for (i = 0; i < UVC_URBS; ++i) {
                urb = usb_alloc_urb(0, gfp_flags);
                if (urb == NULL) {
-                       uvc_uninit_video(video);
-                       return -ENOMEM;
-               }
-
-               video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
-                       size, gfp_flags, &urb->transfer_dma);
-               if (video->urb_buffer[i] == NULL) {
-                       usb_free_urb(urb);
-                       uvc_uninit_video(video);
+                       uvc_uninit_video(video, 1);
                        return -ENOMEM;
                }
 
@@ -692,6 +723,7 @@ static int uvc_init_video_bulk(struct uv
                        video->urb_buffer[i], size, uvc_video_complete,
                        video);
                urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+               urb->transfer_dma = video->urb_dma[i];
 
                video->urb[i] = urb;
        }
@@ -766,7 +798,7 @@ static int uvc_init_video(struct uvc_vid
                if ((ret = usb_submit_urb(video->urb[i], gfp_flags)) < 0) {
                        uvc_printk(KERN_ERR, "Failed to submit URB %u "
                                        "(%d).\n", i, ret);
-                       uvc_uninit_video(video);
+                       uvc_uninit_video(video, 1);
                        return ret;
                }
        }
@@ -791,7 +823,7 @@ int uvc_video_suspend(struct uvc_video_d
                return 0;
 
        video->frozen = 1;
-       uvc_uninit_video(video);
+       uvc_uninit_video(video, 0);
        usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
        return 0;
 }
@@ -920,7 +952,7 @@ int uvc_video_enable(struct uvc_video_de
        int ret;
 
        if (!enable) {
-               uvc_uninit_video(video);
+               uvc_uninit_video(video, 1);
                usb_set_interface(video->dev->udev,
                        video->streaming->intfnum, 0);
                uvc_queue_enable(&video->queue, 0);
diff -r 07c29bcc1199 -r 0276304b76b9 linux/drivers/media/video/uvc/uvcvideo.h
--- a/linux/drivers/media/video/uvc/uvcvideo.h  Fri Jul 04 00:35:26 2008 +0000
+++ b/linux/drivers/media/video/uvc/uvcvideo.h  Fri Jul 04 00:36:21 2008 +0000
@@ -602,6 +602,8 @@ struct uvc_video_device {
 
        struct urb *urb[UVC_URBS];
        char *urb_buffer[UVC_URBS];
+       dma_addr_t urb_dma[UVC_URBS];
+       unsigned int urb_size;
 
        __u8 last_fid;
 };


---

Patch is available at: 
http://linuxtv.org/hg/v4l-dvb/rev/0276304b76b9cb63b0e236c231641e47b45e0386

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to