aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Pugliese <thomas.pugliese@gmail.com>2013-08-09 10:52:13 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-12 16:45:26 -0400
commitec58fad1feb76c323ef47efff1d1e8660ed4644c (patch)
tree5ad1b2fd376bc653943b95e182b612feb12b36c1
parent24f531371de17010f2b1b57d90e42240032e7733 (diff)
wusbcore: fix kernel panic when disconnecting a wireless USB->serial device
This patch fixes a kernel panic that can occur when disconnecting a wireless USB->serial device. When the serial device disconnects, the device cleanup procedure ends up calling usb_hcd_disable_endpoint on the serial device's endpoints. The wusbcore uses the ABORT_RPIPE command to abort all transfers on the given endpoint but it does not properly give back the URBs when the transfer results return from the HWA. This patch prevents the transfer result processing code from bailing out when it sees a WA_XFER_STATUS_ABORTED result code so that these urbs are flushed properly by usb_hcd_disable_endpoint. It also updates wa_urb_dequeue to handle the case where the endpoint has already been cleaned up when usb_kill_urb is called which is where the panic originally occurred. Signed-off-by: Thomas Pugliese <thomas.pugliese@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/wusbcore/wa-xfer.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
index 16968c899493..d3493ca0525d 100644
--- a/drivers/usb/wusbcore/wa-xfer.c
+++ b/drivers/usb/wusbcore/wa-xfer.c
@@ -1226,6 +1226,12 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb)
1226 } 1226 }
1227 spin_lock_irqsave(&xfer->lock, flags); 1227 spin_lock_irqsave(&xfer->lock, flags);
1228 rpipe = xfer->ep->hcpriv; 1228 rpipe = xfer->ep->hcpriv;
1229 if (rpipe == NULL) {
1230 pr_debug("%s: xfer id 0x%08X has no RPIPE. %s",
1231 __func__, wa_xfer_id(xfer),
1232 "Probably already aborted.\n" );
1233 goto out_unlock;
1234 }
1229 /* Check the delayed list -> if there, release and complete */ 1235 /* Check the delayed list -> if there, release and complete */
1230 spin_lock_irqsave(&wa->xfer_list_lock, flags2); 1236 spin_lock_irqsave(&wa->xfer_list_lock, flags2);
1231 if (!list_empty(&xfer->list_node) && xfer->seg == NULL) 1237 if (!list_empty(&xfer->list_node) && xfer->seg == NULL)
@@ -1644,8 +1650,7 @@ static void wa_xfer_result_cb(struct urb *urb)
1644 break; 1650 break;
1645 } 1651 }
1646 usb_status = xfer_result->bTransferStatus & 0x3f; 1652 usb_status = xfer_result->bTransferStatus & 0x3f;
1647 if (usb_status == WA_XFER_STATUS_ABORTED 1653 if (usb_status == WA_XFER_STATUS_NOT_FOUND)
1648 || usb_status == WA_XFER_STATUS_NOT_FOUND)
1649 /* taken care of already */ 1654 /* taken care of already */
1650 break; 1655 break;
1651 xfer_id = xfer_result->dwTransferID; 1656 xfer_id = xfer_result->dwTransferID;