diff options
author | Mayank Rana <mrana@codeaurora.org> | 2015-07-31 15:55:31 -0700 |
---|---|---|
committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:10:09 -0700 |
commit | dbe778eee035c8a32cdc8d18bca1c167113460cb (patch) | |
tree | e0bd88e7037715f787fe5bf04d4190df49f13c24 /drivers/usb | |
parent | 86751cfb339ab9e9e8d0f74efba715b7b1fb944c (diff) |
USB: f_fs: Allow epfile to be opened only once
Due to USB cable disconnect, ADBD closes its epfiles and re-opens the same.
In normal operation the sequence is:
ffs_func_eps_disable() setting epfile->error to 1
ffs_epfile_release() setting epfile->error to 1
ffs_epfile_open() setting epfile->error to 0
In some cases when above sequeunce gets changed, epfile->error is set to 1.
Hence there is no data transfer happening on ep-IN endpoint. Fix this by
not allowing opening of epfiles until it has being successfully released.
Change-Id: I26b9ec1b6218d00cc0965ce3e71fcea49f9bf567
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index cb92758a982c..cdcb3dcf5b95 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -138,6 +138,7 @@ struct ffs_epfile { unsigned char isoc; /* P: ffs->eps_lock */ unsigned char _pad; + atomic_t opened; }; /* ffs_io_data structure ***************************************************/ @@ -947,8 +948,19 @@ ffs_epfile_open(struct inode *inode, struct file *file) if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; + smp_mb__before_atomic(); + if (atomic_read(&epfile->opened)) { + pr_err("%s(): ep(%s) is already opened.\n", + __func__, epfile->name); + return -EBUSY; + } + + smp_mb__before_atomic(); + atomic_set(&epfile->opened, 1); file->private_data = epfile; ffs_data_opened(epfile->ffs); + + smp_mb__before_atomic(); atomic_set(&epfile->error, 0); return 0; @@ -1065,6 +1077,8 @@ ffs_epfile_release(struct inode *inode, struct file *file) ENTER(); + smp_mb__before_atomic(); + atomic_set(&epfile->opened, 0); atomic_set(&epfile->error, 1); ffs_data_closed(epfile->ffs); file->private_data = NULL; @@ -1662,6 +1676,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs) epfile->ffs = ffs; mutex_init(&epfile->mutex); init_waitqueue_head(&epfile->wait); + atomic_set(&epfile->opened, 0); if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]); else @@ -1708,6 +1723,7 @@ static void ffs_func_eps_disable(struct ffs_function *func) spin_lock_irqsave(&func->ffs->eps_lock, flags); do { + smp_mb__before_atomic(); if (epfile) atomic_set(&epfile->error, 1); |