usb: f_fs: check quirk to pad epout buf size when not aligned to maxpacketsize
authorMichal Nazarewicz <mina86@mina86.com>
Mon, 9 Dec 2013 23:55:37 +0000 (15:55 -0800)
committerFelipe Balbi <balbi@ti.com>
Tue, 10 Dec 2013 04:44:07 +0000 (22:44 -0600)
Check gadget.quirk_ep_out_aligned_size to decide if buffer size requires
to be aligned to maxpacketsize of an out endpoint.  ffs_epfile_io() needs
to pad epout buffer to match above condition if quirk is found.

Signed-off-by: Michal Nazarewicz <mina86@mina86.com>
Signed-off-by: David Cohen <david.a.cohen@linux.intel.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/gadget/f_fs.c

index 1222cf9b62d36f31fce74b21f366891432ae4a15..34940439bb189beee720948d5e8ee538ed7aebdb 100644 (file)
@@ -753,9 +753,10 @@ static ssize_t ffs_epfile_io(struct file *file,
                             char __user *buf, size_t len, int read)
 {
        struct ffs_epfile *epfile = file->private_data;
+       struct usb_gadget *gadget = epfile->ffs->gadget;
        struct ffs_ep *ep;
        char *data = NULL;
-       ssize_t ret;
+       ssize_t ret, data_len;
        int halt;
 
        /* Are we still active? */
@@ -788,7 +789,13 @@ static ssize_t ffs_epfile_io(struct file *file,
 
        /* Allocate & copy */
        if (!halt) {
-               data = kmalloc(len, GFP_KERNEL);
+               /*
+                * Controller may require buffer size to be aligned to
+                * maxpacketsize of an out endpoint.
+                */
+               data_len = read ? usb_ep_align_maybe(gadget, ep->ep, len) : len;
+
+               data = kmalloc(data_len, GFP_KERNEL);
                if (unlikely(!data))
                        return -ENOMEM;
 
@@ -823,7 +830,7 @@ static ssize_t ffs_epfile_io(struct file *file,
                req->context  = &done;
                req->complete = ffs_epfile_io_complete;
                req->buf      = data;
-               req->length   = len;
+               req->length   = data_len;
 
                ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
 
@@ -835,9 +842,17 @@ static ssize_t ffs_epfile_io(struct file *file,
                        ret = -EINTR;
                        usb_ep_dequeue(ep->ep, req);
                } else {
+                       /*
+                        * XXX We may end up silently droping data here.
+                        * Since data_len (i.e. req->length) may be bigger
+                        * than len (after being rounded up to maxpacketsize),
+                        * we may end up with more data then user space has
+                        * space for.
+                        */
                        ret = ep->status;
                        if (read && ret > 0 &&
-                           unlikely(copy_to_user(buf, data, ret)))
+                           unlikely(copy_to_user(buf, data,
+                                                 min_t(size_t, ret, len))))
                                ret = -EFAULT;
                }
        }