diff options
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 93 |
1 files changed, 54 insertions, 39 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 71dd27c0d7f2..a24f9bf9c1c0 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1189,6 +1189,7 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, unsigned long value) { struct ffs_epfile *epfile = file->private_data; + struct ffs_ep *ep; int ret; ENTER(); @@ -1196,50 +1197,64 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; + /* Wait for endpoint to be enabled */ + ep = epfile->ep; + if (!ep) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep)); + if (ret) + return -EINTR; + } + spin_lock_irq(&epfile->ffs->eps_lock); - if (likely(epfile->ep)) { - switch (code) { - case FUNCTIONFS_FIFO_STATUS: - ret = usb_ep_fifo_status(epfile->ep->ep); - break; - case FUNCTIONFS_FIFO_FLUSH: - usb_ep_fifo_flush(epfile->ep->ep); - ret = 0; - break; - case FUNCTIONFS_CLEAR_HALT: - ret = usb_ep_clear_halt(epfile->ep->ep); - break; - case FUNCTIONFS_ENDPOINT_REVMAP: - ret = epfile->ep->num; - break; - case FUNCTIONFS_ENDPOINT_DESC: - { - int desc_idx; - struct usb_endpoint_descriptor *desc; - switch (epfile->ffs->gadget->speed) { - case USB_SPEED_SUPER: - desc_idx = 2; - break; - case USB_SPEED_HIGH: - desc_idx = 1; - break; - default: - desc_idx = 0; - } - desc = epfile->ep->descs[desc_idx]; + /* In the meantime, endpoint got disabled or changed. */ + if (epfile->ep != ep) { + spin_unlock_irq(&epfile->ffs->eps_lock); + return -ESHUTDOWN; + } - spin_unlock_irq(&epfile->ffs->eps_lock); - ret = copy_to_user((void *)value, desc, desc->bLength); - if (ret) - ret = -EFAULT; - return ret; - } + switch (code) { + case FUNCTIONFS_FIFO_STATUS: + ret = usb_ep_fifo_status(epfile->ep->ep); + break; + case FUNCTIONFS_FIFO_FLUSH: + usb_ep_fifo_flush(epfile->ep->ep); + ret = 0; + break; + case FUNCTIONFS_CLEAR_HALT: + ret = usb_ep_clear_halt(epfile->ep->ep); + break; + case FUNCTIONFS_ENDPOINT_REVMAP: + ret = epfile->ep->num; + break; + case FUNCTIONFS_ENDPOINT_DESC: + { + int desc_idx; + struct usb_endpoint_descriptor *desc; + + switch (epfile->ffs->gadget->speed) { + case USB_SPEED_SUPER: + desc_idx = 2; + break; + case USB_SPEED_HIGH: + desc_idx = 1; + break; default: - ret = -ENOTTY; + desc_idx = 0; } - } else { - ret = -ENODEV; + desc = epfile->ep->descs[desc_idx]; + + spin_unlock_irq(&epfile->ffs->eps_lock); + ret = copy_to_user((void *)value, desc, desc->bLength); + if (ret) + ret = -EFAULT; + return ret; + } + default: + ret = -ENOTTY; } spin_unlock_irq(&epfile->ffs->eps_lock); |