| From ec58fad1feb76c323ef47efff1d1e8660ed4644c Mon Sep 17 00:00:00 2001 |
| From: Thomas Pugliese <thomas.pugliese@gmail.com> |
| Date: Fri, 9 Aug 2013 09:52:13 -0500 |
| Subject: wusbcore: fix kernel panic when disconnecting a wireless USB->serial device |
| |
| From: Thomas Pugliese <thomas.pugliese@gmail.com> |
| |
| commit ec58fad1feb76c323ef47efff1d1e8660ed4644c upstream. |
| |
| 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> |
| |
| --- |
| drivers/usb/wusbcore/wa-xfer.c | 9 +++++++-- |
| 1 file changed, 7 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/usb/wusbcore/wa-xfer.c |
| +++ b/drivers/usb/wusbcore/wa-xfer.c |
| @@ -1110,6 +1110,12 @@ int wa_urb_dequeue(struct wahc *wa, stru |
| } |
| spin_lock_irqsave(&xfer->lock, flags); |
| rpipe = xfer->ep->hcpriv; |
| + if (rpipe == NULL) { |
| + pr_debug("%s: xfer id 0x%08X has no RPIPE. %s", |
| + __func__, wa_xfer_id(xfer), |
| + "Probably already aborted.\n" ); |
| + goto out_unlock; |
| + } |
| /* Check the delayed list -> if there, release and complete */ |
| spin_lock_irqsave(&wa->xfer_list_lock, flags2); |
| if (!list_empty(&xfer->list_node) && xfer->seg == NULL) |
| @@ -1493,8 +1499,7 @@ static void wa_xfer_result_cb(struct urb |
| break; |
| } |
| usb_status = xfer_result->bTransferStatus & 0x3f; |
| - if (usb_status == WA_XFER_STATUS_ABORTED |
| - || usb_status == WA_XFER_STATUS_NOT_FOUND) |
| + if (usb_status == WA_XFER_STATUS_NOT_FOUND) |
| /* taken care of already */ |
| break; |
| xfer_id = xfer_result->dwTransferID; |