diff options
author | ChandanaKishori Chiluveru <cchilu@codeaurora.org> | 2015-11-13 11:25:52 +0530 |
---|---|---|
committer | Kyle Yan <kyan@codeaurora.org> | 2016-06-10 15:15:10 -0700 |
commit | 8b910ce20edc07cc7eba4381a9d325e35e0741c5 (patch) | |
tree | 0d2851796a29009dc69f65f94e44e61eedddfc21 /drivers/usb | |
parent | 0a9a9f3fe1f8ab25b266676b5684218efab4f0ae (diff) |
usb: gadget: f_mtp: Fix mtp enumeration failure issue
If cable is disconnected while send_file work is in progress,
Endpoints will be disabled and state will be marked as OFFLINE.
As a part of endpoint disable pending requests will be retire out
with -ECONNRESET error. Due to this we will modify the device state
as ERROR in completion callback. If the state is not offline then
we will mark the device state to ready in send_file_work. This results
in mtp driver to not returning any error for next mtp_write operation
and mtp release will not be called.
Hence fix this issue by adding a proper check in completions to not
moving device state to ERROR in case of disconnect.
Change-Id: Idb4e075c89bdf94790a321bc464d30eba546eeaa
Signed-off-by: ChandanaKishori Chiluveru <cchilu@codeaurora.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/function/f_mtp.c | 31 |
1 files changed, 20 insertions, 11 deletions
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index 3f149a5699f6..a255120f841b 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -476,7 +476,7 @@ static void mtp_complete_in(struct usb_ep *ep, struct usb_request *req) { struct mtp_dev *dev = _mtp_dev; - if (req->status != 0) + if (req->status != 0 && dev->state != STATE_OFFLINE) dev->state = STATE_ERROR; mtp_req_put(dev, &dev->tx_idle, req); @@ -489,7 +489,7 @@ static void mtp_complete_out(struct usb_ep *ep, struct usb_request *req) struct mtp_dev *dev = _mtp_dev; dev->rx_done = 1; - if (req->status != 0) + if (req->status != 0 && dev->state != STATE_OFFLINE) dev->state = STATE_ERROR; wake_up(&dev->read_wq); @@ -499,7 +499,7 @@ static void mtp_complete_intr(struct usb_ep *ep, struct usb_request *req) { struct mtp_dev *dev = _mtp_dev; - if (req->status != 0) + if (req->status != 0 && dev->state != STATE_OFFLINE) dev->state = STATE_ERROR; mtp_req_put(dev, &dev->intr_idle, req); @@ -613,7 +613,7 @@ static ssize_t mtp_read(struct file *fp, char __user *buf, ssize_t r = count, xfer, len; int ret = 0; - DBG(cdev, "mtp_read(%zu)\n", count); + DBG(cdev, "mtp_read(%zu) state:%d\n", count, dev->state); /* we will block until we're online */ DBG(cdev, "mtp_read: waiting for online state\n"); @@ -689,7 +689,7 @@ done: dev->state = STATE_READY; spin_unlock_irq(&dev->lock); - DBG(cdev, "mtp_read returning %zd\n", r); + DBG(cdev, "mtp_read returning %zd state:%d\n", r, dev->state); return r; } @@ -704,7 +704,7 @@ static ssize_t mtp_write(struct file *fp, const char __user *buf, int sendZLP = 0; int ret; - DBG(cdev, "mtp_write(%zu)\n", count); + DBG(cdev, "mtp_write(%zu) state:%d\n", count, dev->state); spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) { @@ -743,6 +743,8 @@ static ssize_t mtp_write(struct file *fp, const char __user *buf, ((req = mtp_req_get(dev, &dev->tx_idle)) || dev->state != STATE_BUSY)); if (!req) { + DBG(cdev, "mtp_write request NULL ret:%d state:%d\n", + ret, dev->state); r = ret; break; } @@ -781,7 +783,7 @@ static ssize_t mtp_write(struct file *fp, const char __user *buf, dev->state = STATE_READY; spin_unlock_irq(&dev->lock); - DBG(cdev, "mtp_write returning %zd\n", r); + DBG(cdev, "mtp_write returning %zd state:%d\n", r, dev->state); return r; } @@ -837,6 +839,9 @@ static void send_file_work(struct work_struct *data) break; } if (!req) { + DBG(cdev, + "send_file_work request NULL ret:%d state:%d\n", + ret, dev->state); r = ret; break; } @@ -897,7 +902,7 @@ static void send_file_work(struct work_struct *data) if (req) mtp_req_put(dev, &dev->tx_idle, req); - DBG(cdev, "send_file_work returning %d\n", r); + DBG(cdev, "send_file_work returning %d state:%d\n", r, dev->state); /* write the result */ dev->xfer_result = r; smp_wmb(); @@ -1050,8 +1055,10 @@ static long mtp_send_receive_ioctl(struct file *fp, unsigned code, struct work_struct *work; int ret = -EINVAL; - if (mtp_lock(&dev->ioctl_excl)) + if (mtp_lock(&dev->ioctl_excl)) { + DBG(dev->cdev, "ioctl returning EBUSY state:%d\n", dev->state); return -EBUSY; + } spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) { @@ -1117,7 +1124,7 @@ fail: spin_unlock_irq(&dev->lock); out: mtp_unlock(&dev->ioctl_excl); - DBG(dev->cdev, "ioctl returning %d\n", ret); + DBG(dev->cdev, "ioctl returning %d state:%d\n", ret, dev->state); return ret; } @@ -1231,8 +1238,10 @@ fail: static int mtp_open(struct inode *ip, struct file *fp) { printk(KERN_INFO "mtp_open\n"); - if (mtp_lock(&_mtp_dev->open_excl)) + if (mtp_lock(&_mtp_dev->open_excl)) { + pr_err("%s mtp_release not called returning EBUSY\n", __func__); return -EBUSY; + } /* clear any error condition */ if (_mtp_dev->state != STATE_OFFLINE) |