diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/inode.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index ea8e3160d05..e5ce4f0bb7c 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -933,28 +933,24 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req) static void ep0_complete (struct usb_ep *ep, struct usb_request *req) { struct dev_data *dev = ep->driver_data; + unsigned long flags; int free = 1; /* for control OUT, data must still get to userspace */ + spin_lock_irqsave(&dev->lock, flags); if (!dev->setup_in) { dev->setup_out_error = (req->status != 0); if (!dev->setup_out_error) free = 0; dev->setup_out_ready = 1; ep0_readable (dev); - } else { - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - if (dev->state == STATE_DEV_SETUP) - dev->state = STATE_DEV_CONNECTED; - spin_unlock_irqrestore(&dev->lock, flags); } /* clean up as appropriate */ if (free && req->buf != &dev->rbuf) clean_req (ep, req); req->complete = epio_complete; + spin_unlock_irqrestore(&dev->lock, flags); } static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len) @@ -1036,6 +1032,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) spin_lock_irq (&dev->lock); if (retval) goto done; + + if (dev->state != STATE_DEV_SETUP) { + retval = -ECANCELED; + goto done; + } + dev->state = STATE_DEV_CONNECTED; + if (dev->setup_out_error) retval = -EIO; else { @@ -1187,6 +1190,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) if (dev->setup_in) { retval = setup_req (dev->gadget->ep0, dev->req, len); if (retval == 0) { + dev->state = STATE_DEV_CONNECTED; spin_unlock_irq (&dev->lock); if (copy_from_user (dev->req->buf, buf, len)) retval = -EFAULT; |