summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorChandanaKishori Chiluveru <cchilu@codeaurora.org>2015-11-13 11:25:52 +0530
committerKyle Yan <kyan@codeaurora.org>2016-06-10 15:15:10 -0700
commit8b910ce20edc07cc7eba4381a9d325e35e0741c5 (patch)
tree0d2851796a29009dc69f65f94e44e61eedddfc21 /drivers/usb
parent0a9a9f3fe1f8ab25b266676b5684218efab4f0ae (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.c31
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)