aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/inode.c')
-rw-r--r--drivers/usb/gadget/inode.c80
1 files changed, 55 insertions, 25 deletions
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 4a000d846a93..86924f9cdd7e 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -533,7 +533,8 @@ struct kiocb_priv {
533 struct usb_request *req; 533 struct usb_request *req;
534 struct ep_data *epdata; 534 struct ep_data *epdata;
535 void *buf; 535 void *buf;
536 char __user *ubuf; /* NULL for writes */ 536 const struct iovec *iv;
537 unsigned long nr_segs;
537 unsigned actual; 538 unsigned actual;
538}; 539};
539 540
@@ -561,17 +562,32 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e)
561static ssize_t ep_aio_read_retry(struct kiocb *iocb) 562static ssize_t ep_aio_read_retry(struct kiocb *iocb)
562{ 563{
563 struct kiocb_priv *priv = iocb->private; 564 struct kiocb_priv *priv = iocb->private;
564 ssize_t status = priv->actual; 565 ssize_t len, total;
565 566 int i;
566 /* we "retry" to get the right mm context for this: */ 567
567 status = copy_to_user(priv->ubuf, priv->buf, priv->actual); 568 /* we "retry" to get the right mm context for this: */
568 if (unlikely(0 != status)) 569
569 status = -EFAULT; 570 /* copy stuff into user buffers */
570 else 571 total = priv->actual;
571 status = priv->actual; 572 len = 0;
572 kfree(priv->buf); 573 for (i=0; i < priv->nr_segs; i++) {
573 kfree(priv); 574 ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
574 return status; 575
576 if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
577 if (len == 0)
578 len = -EFAULT;
579 break;
580 }
581
582 total -= this;
583 len += this;
584 if (total == 0)
585 break;
586 }
587 kfree(priv->buf);
588 kfree(priv);
589 aio_put_req(iocb);
590 return len;
575} 591}
576 592
577static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) 593static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -584,7 +600,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
584 spin_lock(&epdata->dev->lock); 600 spin_lock(&epdata->dev->lock);
585 priv->req = NULL; 601 priv->req = NULL;
586 priv->epdata = NULL; 602 priv->epdata = NULL;
587 if (priv->ubuf == NULL 603 if (priv->iv == NULL
588 || unlikely(req->actual == 0) 604 || unlikely(req->actual == 0)
589 || unlikely(kiocbIsCancelled(iocb))) { 605 || unlikely(kiocbIsCancelled(iocb))) {
590 kfree(req->buf); 606 kfree(req->buf);
@@ -619,7 +635,8 @@ ep_aio_rwtail(
619 char *buf, 635 char *buf,
620 size_t len, 636 size_t len,
621 struct ep_data *epdata, 637 struct ep_data *epdata,
622 char __user *ubuf 638 const struct iovec *iv,
639 unsigned long nr_segs
623) 640)
624{ 641{
625 struct kiocb_priv *priv; 642 struct kiocb_priv *priv;
@@ -634,7 +651,8 @@ fail:
634 return value; 651 return value;
635 } 652 }
636 iocb->private = priv; 653 iocb->private = priv;
637 priv->ubuf = ubuf; 654 priv->iv = iv;
655 priv->nr_segs = nr_segs;
638 656
639 value = get_ready_ep(iocb->ki_filp->f_flags, epdata); 657 value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
640 if (unlikely(value < 0)) { 658 if (unlikely(value < 0)) {
@@ -674,41 +692,53 @@ fail:
674 kfree(priv); 692 kfree(priv);
675 put_ep(epdata); 693 put_ep(epdata);
676 } else 694 } else
677 value = (ubuf ? -EIOCBRETRY : -EIOCBQUEUED); 695 value = (iv ? -EIOCBRETRY : -EIOCBQUEUED);
678 return value; 696 return value;
679} 697}
680 698
681static ssize_t 699static ssize_t
682ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) 700ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
701 unsigned long nr_segs, loff_t o)
683{ 702{
684 struct ep_data *epdata = iocb->ki_filp->private_data; 703 struct ep_data *epdata = iocb->ki_filp->private_data;
685 char *buf; 704 char *buf;
686 705
687 if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN)) 706 if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN))
688 return -EINVAL; 707 return -EINVAL;
689 buf = kmalloc(len, GFP_KERNEL); 708
709 buf = kmalloc(iocb->ki_left, GFP_KERNEL);
690 if (unlikely(!buf)) 710 if (unlikely(!buf))
691 return -ENOMEM; 711 return -ENOMEM;
712
692 iocb->ki_retry = ep_aio_read_retry; 713 iocb->ki_retry = ep_aio_read_retry;
693 return ep_aio_rwtail(iocb, buf, len, epdata, ubuf); 714 return ep_aio_rwtail(iocb, buf, iocb->ki_left, epdata, iov, nr_segs);
694} 715}
695 716
696static ssize_t 717static ssize_t
697ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o) 718ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
719 unsigned long nr_segs, loff_t o)
698{ 720{
699 struct ep_data *epdata = iocb->ki_filp->private_data; 721 struct ep_data *epdata = iocb->ki_filp->private_data;
700 char *buf; 722 char *buf;
723 size_t len = 0;
724 int i = 0;
701 725
702 if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN))) 726 if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN)))
703 return -EINVAL; 727 return -EINVAL;
704 buf = kmalloc(len, GFP_KERNEL); 728
729 buf = kmalloc(iocb->ki_left, GFP_KERNEL);
705 if (unlikely(!buf)) 730 if (unlikely(!buf))
706 return -ENOMEM; 731 return -ENOMEM;
707 if (unlikely(copy_from_user(buf, ubuf, len) != 0)) { 732
708 kfree(buf); 733 for (i=0; i < nr_segs; i++) {
709 return -EFAULT; 734 if (unlikely(copy_from_user(&buf[len], iov[i].iov_base,
735 iov[i].iov_len) != 0)) {
736 kfree(buf);
737 return -EFAULT;
738 }
739 len += iov[i].iov_len;
710 } 740 }
711 return ep_aio_rwtail(iocb, buf, len, epdata, NULL); 741 return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0);
712} 742}
713 743
714/*----------------------------------------------------------------------*/ 744/*----------------------------------------------------------------------*/