summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorMayank Rana <mrana@codeaurora.org>2015-11-16 12:31:24 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 19:58:22 -0700
commit3c2bb805ce85ab68dda76cb847f6d222c190846c (patch)
tree9401cfc8c5f15cb4bb5e7a909dac675d87612343 /drivers/usb
parentea1cd34463715f0776b9b992016000277f550841 (diff)
usb: u_data_bridge: Check for USB cable connect with gbridge_port_write()
There is NULL pointer crash seen due to accessing port->port_usb from gbridge_port_write() when port bridge application's write thread is pre-empted and USB cable disconnect is being performed. Fix this issue by adding check for USB cable is connected or not and handling USB request accordingly. Change-Id: Ide14de298b7186cbe7b7af1e99c8c47bc389130b Signed-off-by: Mayank Rana <mrana@codeaurora.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/function/u_data_bridge.c28
1 files changed, 21 insertions, 7 deletions
diff --git a/drivers/usb/gadget/function/u_data_bridge.c b/drivers/usb/gadget/function/u_data_bridge.c
index 1da24304bcd8..253831755a7d 100644
--- a/drivers/usb/gadget/function/u_data_bridge.c
+++ b/drivers/usb/gadget/function/u_data_bridge.c
@@ -508,6 +508,7 @@ ssize_t gbridge_port_write(struct file *file,
struct usb_request *req;
struct list_head *pool;
unsigned xfer_size;
+ struct usb_ep *in;
port = file->private_data;
if (!port) {
@@ -518,11 +519,19 @@ ssize_t gbridge_port_write(struct file *file,
spin_lock_irqsave(&port->port_lock, flags);
pr_debug("write on port(%p)\n", port);
+ if (!port->is_connected || !port->port_usb) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ pr_err("%s: cable is disconnected.\n", __func__);
+ return -ENODEV;
+ }
+
if (list_empty(&port->write_pool)) {
spin_unlock_irqrestore(&port->port_lock, flags);
pr_debug("%s: Request list is empty.\n", __func__);
return 0;
}
+
+ in = port->port_usb->in;
pool = &port->write_pool;
req = list_first_entry(pool, struct usb_request, list);
list_del_init(&req->list);
@@ -540,13 +549,10 @@ ssize_t gbridge_port_write(struct file *file,
ret = -EFAULT;
} else {
req->length = xfer_size;
- ret = usb_ep_queue(port->port_usb->in, req, GFP_KERNEL);
+ ret = usb_ep_queue(in, req, GFP_KERNEL);
if (ret) {
pr_err("EP QUEUE failed:%d\n", ret);
- spin_lock_irqsave(&port->port_lock, flags);
- list_add(&req->list, &port->write_pool);
ret = -EIO;
- spin_unlock_irqrestore(&port->port_lock, flags);
goto err_exit;
}
spin_lock_irqsave(&port->port_lock, flags);
@@ -555,10 +561,18 @@ ssize_t gbridge_port_write(struct file *file,
}
err_exit:
- if (ret)
+ if (ret) {
+ spin_lock_irqsave(&port->port_lock, flags);
+ /* USB cable is connected, add it back otherwise free request */
+ if (port->is_connected)
+ list_add(&req->list, &port->write_pool);
+ else
+ gbridge_free_req(in, req);
+ spin_unlock_irqrestore(&port->port_lock, flags);
return ret;
- else
- return xfer_size;
+ }
+
+ return xfer_size;
}
static unsigned int gbridge_port_poll(struct file *file, poll_table *wait)