diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 19:30:55 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 19:30:55 -0700 |
| commit | 362f6729cbb1d6bbab59e069f19441b0622ff7ec (patch) | |
| tree | 654070221092c34c97f48fbbdef7d5f02ffc7ba4 /drivers/usb/gadget/function/f_fs.c | |
| parent | 4422d80ed7d4bdb2d6e9fb890c66c3d9250ba694 (diff) | |
| parent | 6836796de4019944f4ba4c99a360e8250fd2e735 (diff) | |
| download | linux-362f6729cbb1d6bbab59e069f19441b0622ff7ec.tar.gz linux-362f6729cbb1d6bbab59e069f19441b0622ff7ec.tar.bz2 linux-362f6729cbb1d6bbab59e069f19441b0622ff7ec.zip | |
Merge tag 'usb-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY updates from Greg KH:
"Here is the big patchset of USB and PHY driver updates for 4.13-rc1.
On the PHY side, they decided to move files around to "make things
easier" in their tree. Hopefully that wasn't a mistake, but in
linux-next testing, we haven't had any reported problems.
There's the usual set of gadget and xhci and musb updates in here as
well, along with a number of smaller updates for a raft of different
USB drivers. Full details in the shortlog, nothing really major.
All of these have been in linux-next for a while with no reported
issues"
* tag 'usb-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (173 commits)
Add USB quirk for HVR-950q to avoid intermittent device resets
USB hub_probe: rework ugly goto-into-compound-statement
usb: host: ohci-pxa27x: Handle return value of clk_prepare_enable
USB: serial: cp210x: add ID for CEL EM3588 USB ZigBee stick
usbip: Fix uninitialized variable bug in vhci
usb: core: read USB ports from DT in the usbport LED trigger driver
dt-bindings: leds: document new trigger-sources property
usb: typec: ucsi: Add ACPI driver
usb: typec: Add support for UCSI interface
usb: musb: compress return logic into one line
USB: serial: propagate late probe errors
USB: serial: refactor port endpoint setup
usb: musb: tusb6010_omap: Convert to DMAengine API
ARM: OMAP2+: DMA: Add slave map entries for 24xx external request lines
usb: musb: tusb6010: Handle DMA TX completion in DMA callback as well
usb: musb: tusb6010_omap: Allocate DMA channels upfront
usb: musb: tusb6010_omap: Create new struct for DMA data/parameters
usb: musb: tusb6010_omap: Use one musb_ep_select call in tusb_omap_dma_program
usb: musb: tusb6010: Add MUSB_G_NO_SKB_RESERVE to quirks
usb: musb: Add quirk to avoid skb reserve in gadget mode
...
Diffstat (limited to 'drivers/usb/gadget/function/f_fs.c')
| -rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 110 |
1 files changed, 63 insertions, 47 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 47dda3450abd..d21874b35cf6 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -127,7 +127,6 @@ struct ffs_ep { struct ffs_epfile { /* Protects ep->ep and ep->req. */ struct mutex mutex; - wait_queue_head_t wait; struct ffs_data *ffs; struct ffs_ep *ep; /* P: ffs->eps_lock */ @@ -889,7 +888,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) if (file->f_flags & O_NONBLOCK) return -EAGAIN; - ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep)); + ret = wait_event_interruptible( + epfile->ffs->wait, (ep = epfile->ep)); if (ret) return -EINTR; } @@ -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,65 @@ 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->ffs->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); @@ -1593,7 +1609,8 @@ static void ffs_data_put(struct ffs_data *ffs) pr_info("%s(): freeing\n", __func__); ffs_data_clear(ffs); BUG_ON(waitqueue_active(&ffs->ev.waitq) || - waitqueue_active(&ffs->ep0req_completion.wait)); + waitqueue_active(&ffs->ep0req_completion.wait) || + waitqueue_active(&ffs->wait)); kfree(ffs->dev_name); kfree(ffs); } @@ -1640,6 +1657,7 @@ static struct ffs_data *ffs_data_new(void) mutex_init(&ffs->mutex); spin_lock_init(&ffs->eps_lock); init_waitqueue_head(&ffs->ev.waitq); + init_waitqueue_head(&ffs->wait); init_completion(&ffs->ep0req_completion); /* XXX REVISIT need to update it in some places, or do we? */ @@ -1761,7 +1779,6 @@ static int ffs_epfiles_create(struct ffs_data *ffs) for (i = 1; i <= count; ++i, ++epfile) { epfile->ffs = ffs; mutex_init(&epfile->mutex); - init_waitqueue_head(&epfile->wait); if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]); else @@ -1786,8 +1803,7 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) ENTER(); for (; count; --count, ++epfile) { - BUG_ON(mutex_is_locked(&epfile->mutex) || - waitqueue_active(&epfile->wait)); + BUG_ON(mutex_is_locked(&epfile->mutex)); if (epfile->dentry) { d_delete(epfile->dentry); dput(epfile->dentry); @@ -1874,11 +1890,11 @@ static int ffs_func_eps_enable(struct ffs_function *func) break; } - wake_up(&epfile->wait); - ++ep; ++epfile; } + + wake_up_interruptible(&ffs->wait); spin_unlock_irqrestore(&func->ffs->eps_lock, flags); return ret; |
