diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index c7adc17c1b30..a3862a21db85 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -124,6 +124,7 @@ struct ffs_epfile { /* Protects ep->ep and ep->req. */ struct mutex mutex; wait_queue_head_t wait; + atomic_t error; struct ffs_data *ffs; struct ffs_ep *ep; /* P: ffs->eps_lock */ @@ -703,9 +704,19 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) goto error; } - ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep)); - if (ret) { - ret = -EINTR; + /* + * If ep is disabled, this fails all current IOs + * and wait for next epfile open to happen. + */ + if (!atomic_read(&epfile->error)) { + ret = wait_event_interruptible(epfile->wait, + (ep = epfile->ep)); + if (ret < 0) + goto error; + } + + if (!ep) { + ret = -ENODEV; goto error; } } @@ -830,7 +841,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) spin_unlock_irq(&epfile->ffs->eps_lock); if (unlikely(ret < 0)) { - /* nop */ + ret = -EIO; } else if (unlikely( wait_for_completion_interruptible(&done))) { spin_lock_irq(&epfile->ffs->eps_lock); @@ -885,6 +896,7 @@ ffs_epfile_open(struct inode *inode, struct file *file) file->private_data = epfile; ffs_data_opened(epfile->ffs); + atomic_set(&epfile->error, 0); return 0; } @@ -1000,6 +1012,7 @@ ffs_epfile_release(struct inode *inode, struct file *file) ENTER(); + atomic_set(&epfile->error, 1); ffs_data_closed(epfile->ffs); return 0; @@ -1633,6 +1646,7 @@ static void ffs_func_eps_disable(struct ffs_function *func) ++ep; if (epfile) { + atomic_set(&epfile->error, 1); epfile->ep = NULL; ++epfile; }