aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnson Jacob <ansonjacob.aj@gmail.com>2016-08-12 20:38:10 -0400
committerMister Oyster <oysterized@gmail.com>2017-09-23 16:13:04 +0200
commit02a5ca9d203e207d9b3705996f365c448099c91f (patch)
tree56e87bcee0e0712a1460334d80996a54d0b9c7d2
parent4568b50d355c7140ba0added8fed5380c85efec2 (diff)
downloadandroid_kernel_m2note-02a5ca9d203e207d9b3705996f365c448099c91f.tar.gz
usb: gadget: f_accessory: Fix for UsbAccessory clean unbind.
Reapplying fix by Darren Whobrey (Change 69674) Fixes issues: 20545, 59667 and 61390. With prior version of f_accessory.c, UsbAccessories would not unbind cleanly when application is closed or i/o stopped while the usb cable is still connected. The accessory gadget driver would be left in an invalid state which was not reset on subsequent binding or opening. A reboot was necessary to clear. In some phones this issues causes the phone to reboot upon unplugging the USB cable. Main problem was that acc_disconnect was being called on I/O error which reset disconnected and online. Minor fix required to properly track setting and unsetting of disconnected and online flags. Also added urb Q wakeup's on unbind to help unblock waiting threads. Tested on Nexus 7 grouper. Expected behaviour now observed: closing accessory causes blocked i/o to interrupt with IOException. Accessory can be restarted following closing of file handle and re-opening. This is a generic fix that applies to all devices. Change-Id: I4e08b326730dd3a2820c863124cee10f7cb5501e Signed-off-by: Darren Whobrey <d.whobrey@mildai.org> Signed-off-by: Anson Jacob <ansonjacob.aj@gmail.com> Signed-off-by: Joe Maples <joe@frap129.org>
-rw-r--r--drivers/usb/gadget/f_accessory.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c
index 7b3ebc4eb..41c86ad64 100644
--- a/drivers/usb/gadget/f_accessory.c
+++ b/drivers/usb/gadget/f_accessory.c
@@ -73,9 +73,13 @@ struct acc_dev {
struct usb_ep *ep_in;
struct usb_ep *ep_out;
- /* set to 1 when we connect */
+ /* online indicates state of function_set_alt & function_unbind
+ * set to 1 when we connect
+ */
int online:1;
- /* Set to 1 when we disconnect.
+
+ /* disconnected indicates state of open & release
+ * Set to 1 when we disconnect.
* Not cleared until our file is closed.
*/
int disconnected:1;
@@ -257,7 +261,6 @@ static struct usb_request *req_get(struct acc_dev *dev, struct list_head *head)
static void acc_set_disconnected(struct acc_dev *dev)
{
- dev->online = 0;
dev->disconnected = 1;
}
@@ -759,7 +762,10 @@ static int acc_release(struct inode *ip, struct file *fp)
printk(KERN_INFO "acc_release\n");
WARN_ON(!atomic_xchg(&_acc_dev->open_excl, 0));
- _acc_dev->disconnected = 0;
+ /* indicate that we are disconnected
+ * still could be online so don't touch online flag
+ */
+ _acc_dev->disconnected = 1;
return 0;
}
@@ -986,6 +992,10 @@ acc_function_unbind(struct usb_configuration *c, struct usb_function *f)
struct usb_request *req;
int i;
+ dev->online = 0; /* clear online flag */
+ wake_up(&dev->read_wq); /* unblock reads on closure */
+ wake_up(&dev->write_wq); /* likewise for writes */
+
while ((req = req_get(dev, &dev->tx_idle)))
acc_request_free(req, dev->ep_in);
for (i = 0; i < RX_REQ_MAX; i++)
@@ -1116,6 +1126,7 @@ static int acc_function_set_alt(struct usb_function *f,
}
dev->online = 1;
+ dev->disconnected = 0; /* if online then not disconnected */
/* readers may be blocked waiting for us to go online */
wake_up(&dev->read_wq);
@@ -1128,7 +1139,8 @@ static void acc_function_disable(struct usb_function *f)
struct usb_composite_dev *cdev = dev->cdev;
DBG(cdev, "acc_function_disable\n");
- acc_set_disconnected(dev);
+ acc_set_disconnected(dev); /* this now only sets disconnected */
+ dev->online = 0; /* so now need to clear online flag here too */
usb_ep_disable(dev->ep_in);
usb_ep_disable(dev->ep_out);