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");