aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/whci/pzl.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/pzl.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/pzl.c')
-rw-r--r--drivers/usb/host/whci/pzl.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c
index a9e05bac6646..e923633f30c1 100644
--- a/drivers/usb/host/whci/pzl.c
+++ b/drivers/usb/host/whci/pzl.c
@@ -333,6 +333,7 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
333 struct whc_urb *wurb = urb->hcpriv; 333 struct whc_urb *wurb = urb->hcpriv;
334 struct whc_qset *qset = wurb->qset; 334 struct whc_qset *qset = wurb->qset;
335 struct whc_std *std, *t; 335 struct whc_std *std, *t;
336 bool has_qtd = false;
336 int ret; 337 int ret;
337 unsigned long flags; 338 unsigned long flags;
338 339
@@ -343,17 +344,22 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
343 goto out; 344 goto out;
344 345
345 list_for_each_entry_safe(std, t, &qset->stds, list_node) { 346 list_for_each_entry_safe(std, t, &qset->stds, list_node) {
346 if (std->urb == urb) 347 if (std->urb == urb) {
348 if (std->qtd)
349 has_qtd = true;
347 qset_free_std(whc, std); 350 qset_free_std(whc, std);
348 else 351 } else
349 std->qtd = NULL; /* so this std is re-added when the qset is */ 352 std->qtd = NULL; /* so this std is re-added when the qset is */
350 } 353 }
351 354
352 pzl_qset_remove(whc, qset); 355 if (has_qtd) {
353 wurb->status = status; 356 pzl_qset_remove(whc, qset);
354 wurb->is_async = false; 357 update_pzl_hw_view(whc);
355 queue_work(whc->workqueue, &wurb->dequeue_work); 358 wurb->status = status;
356 359 wurb->is_async = false;
360 queue_work(whc->workqueue, &wurb->dequeue_work);
361 } else
362 qset_remove_urb(whc, qset, urb, status);
357out: 363out:
358 spin_unlock_irqrestore(&whc->lock, flags); 364 spin_unlock_irqrestore(&whc->lock, flags);
359 365