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-20 11:43:05 -0400
commitf34a4837cd0b28abe7449e591a23cb32ab128520 (patch)
tree545fb90294b2545d40b0d4a08acbde9068c9ea14
parent1dba303727f52ea062580b0a9b3f0c3b462769cf (diff)
wusbcore: fix kernel panic when disconnecting a wireless USB->serial device
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>
-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 6ef94bce8c0d..028fc8337435 100644
--- 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, struct urb *urb)
1110 } 1110 }
1111 spin_lock_irqsave(&xfer->lock, flags); 1111 spin_lock_irqsave(&xfer->lock, flags);
1112 rpipe = xfer->ep->hcpriv; 1112 rpipe = xfer->ep->hcpriv;
1113 if (rpipe == NULL) {
1114 pr_debug("%s: xfer id 0x%08X has no RPIPE. %s",
1115 __func__, wa_xfer_id(xfer),
1116 "Probably already aborted.\n" );
1117 goto out_unlock;
1118 }
1113 /* Check the delayed list -> if there, release and complete */ 1119 /* Check the delayed list -> if there, release and complete */
1114 spin_lock_irqsave(&wa->xfer_list_lock, flags2); 1120 spin_lock_irqsave(&wa->xfer_list_lock, flags2);
1115 if (!list_empty(&xfer->list_node) && xfer->seg == NULL) 1121 if (!list_empty(&xfer->list_node) && xfer->seg == NULL)
@@ -1493,8 +1499,7 @@ static void wa_xfer_result_cb(struct urb *urb)
1493 break; 1499 break;
1494 } 1500 }
1495 usb_status = xfer_result->bTransferStatus & 0x3f; 1501 usb_status = xfer_result->bTransferStatus & 0x3f;
1496 if (usb_status == WA_XFER_STATUS_ABORTED 1502 if (usb_status == WA_XFER_STATUS_NOT_FOUND)
1497 || usb_status == WA_XFER_STATUS_NOT_FOUND)
1498 /* taken care of already */ 1503 /* taken care of already */
1499 break; 1504 break;
1500 xfer_id = xfer_result->dwTransferID; 1505 xfer_id = xfer_result->dwTransferID;