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>
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index 6d57ed6..9e00cc0 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -453,7 +453,7 @@
{
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);
@@ -466,7 +466,7 @@
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);
@@ -476,7 +476,7 @@
{
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);
@@ -590,7 +590,7 @@
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");
@@ -666,7 +666,7 @@
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;
}
@@ -681,7 +681,7 @@
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) {
@@ -720,6 +720,8 @@
((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;
}
@@ -758,7 +760,7 @@
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;
}
@@ -814,6 +816,9 @@
break;
}
if (!req) {
+ DBG(cdev,
+ "send_file_work request NULL ret:%d state:%d\n",
+ ret, dev->state);
r = ret;
break;
}
@@ -866,7 +871,7 @@
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();
@@ -1019,8 +1024,10 @@
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) {
@@ -1086,7 +1093,7 @@
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;
}
@@ -1200,8 +1207,10 @@
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)