aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/whci/asl.c
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@csr.com>2009-10-12 11:45:15 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-10-14 17:54:42 -0400
commit171b37ee95865c052a88d52a05895c3c584f4871 (patch)
tree6bfd5bf907ce1cf3b7c5a332bb12e5467e0d11c2 /drivers/usb/host/whci/asl.c
parentb41ecf9a80a55406eb4bf90c1ba260785002e103 (diff)
USB: whci-hcd: handle early deletion of endpoints
If an endpoint is deleted before it's been fully added to the hardware list, the associated qset will not be fully initialized and an oops will occur when complete(&qset->remove_complete) is called. This can happen if a queued URB is cancelled. Fix this by only removing the qset from the hardware list if the cancelled URB had qTDs. Signed-off-by: David Vrabel <david.vrabel@csr.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/whci/asl.c')
-rw-r--r--drivers/usb/host/whci/asl.c19
1 files changed, 12 insertions, 7 deletions
diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c
index c632437c7649..14ccbcfc4315 100644
--- a/drivers/usb/host/whci/asl.c
+++ b/drivers/usb/host/whci/asl.c
@@ -305,6 +305,7 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
305 struct whc_urb *wurb = urb->hcpriv; 305 struct whc_urb *wurb = urb->hcpriv;
306 struct whc_qset *qset = wurb->qset; 306 struct whc_qset *qset = wurb->qset;
307 struct whc_std *std, *t; 307 struct whc_std *std, *t;
308 bool has_qtd = false;
308 int ret; 309 int ret;
309 unsigned long flags; 310 unsigned long flags;
310 311
@@ -315,17 +316,21 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
315 goto out; 316 goto out;
316 317
317 list_for_each_entry_safe(std, t, &qset->stds, list_node) { 318 list_for_each_entry_safe(std, t, &qset->stds, list_node) {
318 if (std->urb == urb) 319 if (std->urb == urb) {
320 if (std->qtd)
321 has_qtd = true;
319 qset_free_std(whc, std); 322 qset_free_std(whc, std);
320 else 323 } else
321 std->qtd = NULL; /* so this std is re-added when the qset is */ 324 std->qtd = NULL; /* so this std is re-added when the qset is */
322 } 325 }
323 326
324 asl_qset_remove(whc, qset); 327 if (has_qtd) {
325 wurb->status = status; 328 asl_qset_remove(whc, qset);
326 wurb->is_async = true; 329 wurb->status = status;
327 queue_work(whc->workqueue, &wurb->dequeue_work); 330 wurb->is_async = true;
328 331 queue_work(whc->workqueue, &wurb->dequeue_work);
332 } else
333 qset_remove_urb(whc, qset, urb, status);
329out: 334out:
330 spin_unlock_irqrestore(&whc->lock, flags); 335 spin_unlock_irqrestore(&whc->lock, flags);
331 336