diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/usb/gadget/legacy/inode.c | 90 |
1 files changed, 37 insertions, 53 deletions
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index b825edcbf387..c0e25320a3c4 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c | |||
| @@ -74,6 +74,8 @@ MODULE_DESCRIPTION (DRIVER_DESC); | |||
| 74 | MODULE_AUTHOR ("David Brownell"); | 74 | MODULE_AUTHOR ("David Brownell"); |
| 75 | MODULE_LICENSE ("GPL"); | 75 | MODULE_LICENSE ("GPL"); |
| 76 | 76 | ||
| 77 | static int ep_open(struct inode *, struct file *); | ||
| 78 | |||
| 77 | 79 | ||
| 78 | /*----------------------------------------------------------------------*/ | 80 | /*----------------------------------------------------------------------*/ |
| 79 | 81 | ||
| @@ -283,14 +285,15 @@ static void epio_complete (struct usb_ep *ep, struct usb_request *req) | |||
| 283 | * still need dev->lock to use epdata->ep. | 285 | * still need dev->lock to use epdata->ep. |
| 284 | */ | 286 | */ |
| 285 | static int | 287 | static int |
| 286 | get_ready_ep (unsigned f_flags, struct ep_data *epdata) | 288 | get_ready_ep (unsigned f_flags, struct ep_data *epdata, bool is_write) |
| 287 | { | 289 | { |
| 288 | int val; | 290 | int val; |
| 289 | 291 | ||
| 290 | if (f_flags & O_NONBLOCK) { | 292 | if (f_flags & O_NONBLOCK) { |
| 291 | if (!mutex_trylock(&epdata->lock)) | 293 | if (!mutex_trylock(&epdata->lock)) |
| 292 | goto nonblock; | 294 | goto nonblock; |
| 293 | if (epdata->state != STATE_EP_ENABLED) { | 295 | if (epdata->state != STATE_EP_ENABLED && |
| 296 | (!is_write || epdata->state != STATE_EP_READY)) { | ||
| 294 | mutex_unlock(&epdata->lock); | 297 | mutex_unlock(&epdata->lock); |
| 295 | nonblock: | 298 | nonblock: |
| 296 | val = -EAGAIN; | 299 | val = -EAGAIN; |
| @@ -305,18 +308,20 @@ nonblock: | |||
| 305 | 308 | ||
| 306 | switch (epdata->state) { | 309 | switch (epdata->state) { |
| 307 | case STATE_EP_ENABLED: | 310 | case STATE_EP_ENABLED: |
| 311 | return 0; | ||
| 312 | case STATE_EP_READY: /* not configured yet */ | ||
| 313 | if (is_write) | ||
| 314 | return 0; | ||
| 315 | // FALLTHRU | ||
| 316 | case STATE_EP_UNBOUND: /* clean disconnect */ | ||
| 308 | break; | 317 | break; |
| 309 | // case STATE_EP_DISABLED: /* "can't happen" */ | 318 | // case STATE_EP_DISABLED: /* "can't happen" */ |
| 310 | // case STATE_EP_READY: /* "can't happen" */ | ||
| 311 | default: /* error! */ | 319 | default: /* error! */ |
| 312 | pr_debug ("%s: ep %p not available, state %d\n", | 320 | pr_debug ("%s: ep %p not available, state %d\n", |
| 313 | shortname, epdata, epdata->state); | 321 | shortname, epdata, epdata->state); |
| 314 | // FALLTHROUGH | ||
| 315 | case STATE_EP_UNBOUND: /* clean disconnect */ | ||
| 316 | val = -ENODEV; | ||
| 317 | mutex_unlock(&epdata->lock); | ||
| 318 | } | 322 | } |
| 319 | return val; | 323 | mutex_unlock(&epdata->lock); |
| 324 | return -ENODEV; | ||
| 320 | } | 325 | } |
| 321 | 326 | ||
| 322 | static ssize_t | 327 | static ssize_t |
| @@ -390,7 +395,7 @@ static long ep_ioctl(struct file *fd, unsigned code, unsigned long value) | |||
| 390 | struct ep_data *data = fd->private_data; | 395 | struct ep_data *data = fd->private_data; |
| 391 | int status; | 396 | int status; |
| 392 | 397 | ||
| 393 | if ((status = get_ready_ep (fd->f_flags, data)) < 0) | 398 | if ((status = get_ready_ep (fd->f_flags, data, false)) < 0) |
| 394 | return status; | 399 | return status; |
| 395 | 400 | ||
| 396 | spin_lock_irq (&data->dev->lock); | 401 | spin_lock_irq (&data->dev->lock); |
| @@ -572,7 +577,7 @@ ep_read_iter(struct kiocb *iocb, struct iov_iter *to) | |||
| 572 | ssize_t value; | 577 | ssize_t value; |
| 573 | char *buf; | 578 | char *buf; |
| 574 | 579 | ||
| 575 | if ((value = get_ready_ep(file->f_flags, epdata)) < 0) | 580 | if ((value = get_ready_ep(file->f_flags, epdata, false)) < 0) |
| 576 | return value; | 581 | return value; |
| 577 | 582 | ||
| 578 | /* halt any endpoint by doing a "wrong direction" i/o call */ | 583 | /* halt any endpoint by doing a "wrong direction" i/o call */ |
| @@ -620,20 +625,25 @@ fail: | |||
| 620 | return value; | 625 | return value; |
| 621 | } | 626 | } |
| 622 | 627 | ||
| 628 | static ssize_t ep_config(struct ep_data *, const char *, size_t); | ||
| 629 | |||
| 623 | static ssize_t | 630 | static ssize_t |
| 624 | ep_write_iter(struct kiocb *iocb, struct iov_iter *from) | 631 | ep_write_iter(struct kiocb *iocb, struct iov_iter *from) |
| 625 | { | 632 | { |
| 626 | struct file *file = iocb->ki_filp; | 633 | struct file *file = iocb->ki_filp; |
| 627 | struct ep_data *epdata = file->private_data; | 634 | struct ep_data *epdata = file->private_data; |
| 628 | size_t len = iov_iter_count(from); | 635 | size_t len = iov_iter_count(from); |
| 636 | bool configured; | ||
| 629 | ssize_t value; | 637 | ssize_t value; |
| 630 | char *buf; | 638 | char *buf; |
| 631 | 639 | ||
| 632 | if ((value = get_ready_ep(file->f_flags, epdata)) < 0) | 640 | if ((value = get_ready_ep(file->f_flags, epdata, true)) < 0) |
| 633 | return value; | 641 | return value; |
| 634 | 642 | ||
| 643 | configured = epdata->state == STATE_EP_ENABLED; | ||
| 644 | |||
| 635 | /* halt any endpoint by doing a "wrong direction" i/o call */ | 645 | /* halt any endpoint by doing a "wrong direction" i/o call */ |
| 636 | if (!usb_endpoint_dir_in(&epdata->desc)) { | 646 | if (configured && !usb_endpoint_dir_in(&epdata->desc)) { |
| 637 | if (usb_endpoint_xfer_isoc(&epdata->desc) || | 647 | if (usb_endpoint_xfer_isoc(&epdata->desc) || |
| 638 | !is_sync_kiocb(iocb)) { | 648 | !is_sync_kiocb(iocb)) { |
| 639 | mutex_unlock(&epdata->lock); | 649 | mutex_unlock(&epdata->lock); |
| @@ -659,7 +669,9 @@ ep_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
| 659 | goto out; | 669 | goto out; |
| 660 | } | 670 | } |
| 661 | 671 | ||
| 662 | if (is_sync_kiocb(iocb)) { | 672 | if (unlikely(!configured)) { |
| 673 | value = ep_config(epdata, buf, len); | ||
| 674 | } else if (is_sync_kiocb(iocb)) { | ||
| 663 | value = ep_io(epdata, buf, len); | 675 | value = ep_io(epdata, buf, len); |
| 664 | } else { | 676 | } else { |
| 665 | struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL); | 677 | struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL); |
| @@ -681,13 +693,13 @@ out: | |||
| 681 | /* used after endpoint configuration */ | 693 | /* used after endpoint configuration */ |
| 682 | static const struct file_operations ep_io_operations = { | 694 | static const struct file_operations ep_io_operations = { |
| 683 | .owner = THIS_MODULE, | 695 | .owner = THIS_MODULE, |
| 684 | .llseek = no_llseek, | ||
| 685 | 696 | ||
| 697 | .open = ep_open, | ||
| 698 | .release = ep_release, | ||
| 699 | .llseek = no_llseek, | ||
| 686 | .read = new_sync_read, | 700 | .read = new_sync_read, |
| 687 | .write = new_sync_write, | 701 | .write = new_sync_write, |
| 688 | .unlocked_ioctl = ep_ioctl, | 702 | .unlocked_ioctl = ep_ioctl, |
| 689 | .release = ep_release, | ||
| 690 | |||
| 691 | .read_iter = ep_read_iter, | 703 | .read_iter = ep_read_iter, |
| 692 | .write_iter = ep_write_iter, | 704 | .write_iter = ep_write_iter, |
| 693 | }; | 705 | }; |
| @@ -706,17 +718,12 @@ static const struct file_operations ep_io_operations = { | |||
| 706 | * speed descriptor, then optional high speed descriptor. | 718 | * speed descriptor, then optional high speed descriptor. |
| 707 | */ | 719 | */ |
| 708 | static ssize_t | 720 | static ssize_t |
| 709 | ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) | 721 | ep_config (struct ep_data *data, const char *buf, size_t len) |
| 710 | { | 722 | { |
| 711 | struct ep_data *data = fd->private_data; | ||
| 712 | struct usb_ep *ep; | 723 | struct usb_ep *ep; |
| 713 | u32 tag; | 724 | u32 tag; |
| 714 | int value, length = len; | 725 | int value, length = len; |
| 715 | 726 | ||
| 716 | value = mutex_lock_interruptible(&data->lock); | ||
| 717 | if (value < 0) | ||
| 718 | return value; | ||
| 719 | |||
| 720 | if (data->state != STATE_EP_READY) { | 727 | if (data->state != STATE_EP_READY) { |
| 721 | value = -EL2HLT; | 728 | value = -EL2HLT; |
| 722 | goto fail; | 729 | goto fail; |
| @@ -727,9 +734,7 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) | |||
| 727 | goto fail0; | 734 | goto fail0; |
| 728 | 735 | ||
| 729 | /* we might need to change message format someday */ | 736 | /* we might need to change message format someday */ |
| 730 | if (copy_from_user (&tag, buf, 4)) { | 737 | memcpy(&tag, buf, 4); |
| 731 | goto fail1; | ||
| 732 | } | ||
| 733 | if (tag != 1) { | 738 | if (tag != 1) { |
| 734 | DBG(data->dev, "config %s, bad tag %d\n", data->name, tag); | 739 | DBG(data->dev, "config %s, bad tag %d\n", data->name, tag); |
| 735 | goto fail0; | 740 | goto fail0; |
| @@ -742,19 +747,15 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) | |||
| 742 | */ | 747 | */ |
| 743 | 748 | ||
| 744 | /* full/low speed descriptor, then high speed */ | 749 | /* full/low speed descriptor, then high speed */ |
| 745 | if (copy_from_user (&data->desc, buf, USB_DT_ENDPOINT_SIZE)) { | 750 | memcpy(&data->desc, buf, USB_DT_ENDPOINT_SIZE); |
| 746 | goto fail1; | ||
| 747 | } | ||
| 748 | if (data->desc.bLength != USB_DT_ENDPOINT_SIZE | 751 | if (data->desc.bLength != USB_DT_ENDPOINT_SIZE |
| 749 | || data->desc.bDescriptorType != USB_DT_ENDPOINT) | 752 | || data->desc.bDescriptorType != USB_DT_ENDPOINT) |
| 750 | goto fail0; | 753 | goto fail0; |
| 751 | if (len != USB_DT_ENDPOINT_SIZE) { | 754 | if (len != USB_DT_ENDPOINT_SIZE) { |
| 752 | if (len != 2 * USB_DT_ENDPOINT_SIZE) | 755 | if (len != 2 * USB_DT_ENDPOINT_SIZE) |
| 753 | goto fail0; | 756 | goto fail0; |
| 754 | if (copy_from_user (&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE, | 757 | memcpy(&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE, |
| 755 | USB_DT_ENDPOINT_SIZE)) { | 758 | USB_DT_ENDPOINT_SIZE); |
| 756 | goto fail1; | ||
| 757 | } | ||
| 758 | if (data->hs_desc.bLength != USB_DT_ENDPOINT_SIZE | 759 | if (data->hs_desc.bLength != USB_DT_ENDPOINT_SIZE |
| 759 | || data->hs_desc.bDescriptorType | 760 | || data->hs_desc.bDescriptorType |
| 760 | != USB_DT_ENDPOINT) { | 761 | != USB_DT_ENDPOINT) { |
| @@ -776,24 +777,20 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) | |||
| 776 | case USB_SPEED_LOW: | 777 | case USB_SPEED_LOW: |
| 777 | case USB_SPEED_FULL: | 778 | case USB_SPEED_FULL: |
| 778 | ep->desc = &data->desc; | 779 | ep->desc = &data->desc; |
| 779 | value = usb_ep_enable(ep); | ||
| 780 | if (value == 0) | ||
| 781 | data->state = STATE_EP_ENABLED; | ||
| 782 | break; | 780 | break; |
| 783 | case USB_SPEED_HIGH: | 781 | case USB_SPEED_HIGH: |
| 784 | /* fails if caller didn't provide that descriptor... */ | 782 | /* fails if caller didn't provide that descriptor... */ |
| 785 | ep->desc = &data->hs_desc; | 783 | ep->desc = &data->hs_desc; |
| 786 | value = usb_ep_enable(ep); | ||
| 787 | if (value == 0) | ||
| 788 | data->state = STATE_EP_ENABLED; | ||
| 789 | break; | 784 | break; |
| 790 | default: | 785 | default: |
| 791 | DBG(data->dev, "unconnected, %s init abandoned\n", | 786 | DBG(data->dev, "unconnected, %s init abandoned\n", |
| 792 | data->name); | 787 | data->name); |
| 793 | value = -EINVAL; | 788 | value = -EINVAL; |
| 789 | goto gone; | ||
| 794 | } | 790 | } |
| 791 | value = usb_ep_enable(ep); | ||
| 795 | if (value == 0) { | 792 | if (value == 0) { |
| 796 | fd->f_op = &ep_io_operations; | 793 | data->state = STATE_EP_ENABLED; |
| 797 | value = length; | 794 | value = length; |
| 798 | } | 795 | } |
| 799 | gone: | 796 | gone: |
| @@ -803,14 +800,10 @@ fail: | |||
| 803 | data->desc.bDescriptorType = 0; | 800 | data->desc.bDescriptorType = 0; |
| 804 | data->hs_desc.bDescriptorType = 0; | 801 | data->hs_desc.bDescriptorType = 0; |
| 805 | } | 802 | } |
| 806 | mutex_unlock(&data->lock); | ||
| 807 | return value; | 803 | return value; |
| 808 | fail0: | 804 | fail0: |
| 809 | value = -EINVAL; | 805 | value = -EINVAL; |
| 810 | goto fail; | 806 | goto fail; |
| 811 | fail1: | ||
| 812 | value = -EFAULT; | ||
| 813 | goto fail; | ||
| 814 | } | 807 | } |
| 815 | 808 | ||
| 816 | static int | 809 | static int |
| @@ -838,15 +831,6 @@ ep_open (struct inode *inode, struct file *fd) | |||
| 838 | return value; | 831 | return value; |
| 839 | } | 832 | } |
| 840 | 833 | ||
| 841 | /* used before endpoint configuration */ | ||
| 842 | static const struct file_operations ep_config_operations = { | ||
| 843 | .llseek = no_llseek, | ||
| 844 | |||
| 845 | .open = ep_open, | ||
| 846 | .write = ep_config, | ||
| 847 | .release = ep_release, | ||
| 848 | }; | ||
| 849 | |||
| 850 | /*----------------------------------------------------------------------*/ | 834 | /*----------------------------------------------------------------------*/ |
| 851 | 835 | ||
| 852 | /* EP0 IMPLEMENTATION can be partly in userspace. | 836 | /* EP0 IMPLEMENTATION can be partly in userspace. |
| @@ -1586,7 +1570,7 @@ static int activate_ep_files (struct dev_data *dev) | |||
| 1586 | goto enomem1; | 1570 | goto enomem1; |
| 1587 | 1571 | ||
| 1588 | data->dentry = gadgetfs_create_file (dev->sb, data->name, | 1572 | data->dentry = gadgetfs_create_file (dev->sb, data->name, |
| 1589 | data, &ep_config_operations); | 1573 | data, &ep_io_operations); |
| 1590 | if (!data->dentry) | 1574 | if (!data->dentry) |
| 1591 | goto enomem2; | 1575 | goto enomem2; |
| 1592 | list_add_tail (&data->epfiles, &dev->epfiles); | 1576 | list_add_tail (&data->epfiles, &dev->epfiles); |
