diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index c9f20a203fc..8d82b0f13f1 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -141,6 +141,8 @@ struct ffs_data { struct usb_request *ep0req; /* P: mutex */ struct completion ep0req_completion; /* P: mutex */ int ep0req_status; /* P: mutex */ + struct completion epin_completion; + struct completion epout_completion; /* reference counter */ atomic_t ref; @@ -749,8 +751,11 @@ static const struct file_operations ffs_ep0_operations = { static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) { + struct ffs_ep *ep = _ep->driver_data; ENTER(); - if (likely(req->context)) { + + /* req may be freed during unbind */ + if (ep && ep->req && likely(req->context)) { struct ffs_ep *ep = _ep->driver_data; ep->status = req->status ? req->status : req->actual; complete(req->context); @@ -762,6 +767,7 @@ static ssize_t ffs_epfile_io(struct file *file, { struct ffs_epfile *epfile = file->private_data; struct ffs_ep *ep; + struct ffs_data *ffs = epfile->ffs; char *data = NULL; ssize_t ret; int halt; @@ -860,21 +866,27 @@ static ssize_t ffs_epfile_io(struct file *file, ret = -EBADMSG; } else { /* Fire the request */ - DECLARE_COMPLETION_ONSTACK(done); + struct completion *done; struct usb_request *req = ep->req; - req->context = &done; req->complete = ffs_epfile_io_complete; req->buf = data; req->length = buffer_len; + if (read) { + INIT_COMPLETION(ffs->epout_completion); + req->context = done = &ffs->epout_completion; + } else { + INIT_COMPLETION(ffs->epin_completion); + req->context = done = &ffs->epin_completion; + } ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); spin_unlock_irq(&epfile->ffs->eps_lock); if (unlikely(ret < 0)) { ret = -EIO; - } else if (unlikely(wait_for_completion_interruptible(&done))) { + } else if (unlikely(wait_for_completion_interruptible(done))) { spin_lock_irq(&epfile->ffs->eps_lock); /* * While we were acquiring lock endpoint got disabled @@ -1365,6 +1377,8 @@ static struct ffs_data *ffs_data_new(void) spin_lock_init(&ffs->eps_lock); init_waitqueue_head(&ffs->ev.waitq); init_completion(&ffs->ep0req_completion); + init_completion(&ffs->epout_completion); + init_completion(&ffs->epin_completion); /* XXX REVISIT need to update it in some places, or do we? */ ffs->ev.can_stall = 1;