Commit ec58fad1 authored by Thomas Pugliese's avatar Thomas Pugliese Committed by Greg Kroah-Hartman

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: default avatarThomas Pugliese <thomas.pugliese@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 24f53137
...@@ -1226,6 +1226,12 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb) ...@@ -1226,6 +1226,12 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb)
} }
spin_lock_irqsave(&xfer->lock, flags); spin_lock_irqsave(&xfer->lock, flags);
rpipe = xfer->ep->hcpriv; 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 */ /* Check the delayed list -> if there, release and complete */
spin_lock_irqsave(&wa->xfer_list_lock, flags2); spin_lock_irqsave(&wa->xfer_list_lock, flags2);
if (!list_empty(&xfer->list_node) && xfer->seg == NULL) if (!list_empty(&xfer->list_node) && xfer->seg == NULL)
...@@ -1644,8 +1650,7 @@ static void wa_xfer_result_cb(struct urb *urb) ...@@ -1644,8 +1650,7 @@ static void wa_xfer_result_cb(struct urb *urb)
break; break;
} }
usb_status = xfer_result->bTransferStatus & 0x3f; usb_status = xfer_result->bTransferStatus & 0x3f;
if (usb_status == WA_XFER_STATUS_ABORTED if (usb_status == WA_XFER_STATUS_NOT_FOUND)
|| usb_status == WA_XFER_STATUS_NOT_FOUND)
/* taken care of already */ /* taken care of already */
break; break;
xfer_id = xfer_result->dwTransferID; xfer_id = xfer_result->dwTransferID;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment