usb: diag_bridge: Treat EPROTO as a non-recoverable error

When a read or write callback returns -EPROTO, treat it as if the
device is disconnected and disallow further calls to read and write
by returning -ESHUTDOWN. This will allow the caller to gracefully
handle the error until a disconnect event finally comes and is able
to notify the caller via a platform_device removal.

Change-Id: I65cab1ea94e529743cba695e3c510c501a0e388e
Signed-off-by: Jack Pham <jackp@codeaurora.org>
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 00b2ec1..9b60f70 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -31,6 +31,7 @@
 	struct usb_anchor	submitted;
 	__u8			in_epAddr;
 	__u8			out_epAddr;
+	int			err;
 	struct kref		kref;
 	struct diag_bridge_ops	*ops;
 	struct platform_device	*pdev;
@@ -47,6 +48,7 @@
 	}
 
 	dev->ops = ops;
+	dev->err = 0;
 
 	return 0;
 }
@@ -72,6 +74,12 @@
 	dev_dbg(&dev->udev->dev, "%s: status:%d actual:%d\n", __func__,
 			urb->status, urb->actual_length);
 
+	if (urb->status == -EPROTO) {
+		/* save error so that subsequent read/write returns ESHUTDOWN */
+		dev->err = urb->status;
+		return;
+	}
+
 	cbs->read_complete_cb(cbs->ctxt,
 			urb->transfer_buffer,
 			urb->transfer_buffer_length,
@@ -97,6 +105,10 @@
 		return -ENODEV;
 	}
 
+	/* if there was a previous unrecoverable error, just quit */
+	if (dev->err)
+		return -ESHUTDOWN;
+
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!urb) {
 		dev_err(&dev->udev->dev, "unable to allocate urb\n");
@@ -129,6 +141,12 @@
 
 	dev_dbg(&dev->udev->dev, "%s:\n", __func__);
 
+	if (urb->status == -EPROTO) {
+		/* save error so that subsequent read/write returns ESHUTDOWN */
+		dev->err = urb->status;
+		return;
+	}
+
 	cbs->write_complete_cb(cbs->ctxt,
 			urb->transfer_buffer,
 			urb->transfer_buffer_length,
@@ -154,6 +172,10 @@
 		return -ENODEV;
 	}
 
+	/* if there was a previous unrecoverable error, just quit */
+	if (dev->err)
+		return -ESHUTDOWN;
+
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!urb) {
 		err("unable to allocate urb");