summaryrefslogtreecommitdiff
path: root/drivers/usb/host/whci/pzl.c
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@csr.com>2009-10-12 19:45:15 +0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-10-15 01:54:42 +0400
commit171b37ee95865c052a88d52a05895c3c584f4871 (patch)
tree6bfd5bf907ce1cf3b7c5a332bb12e5467e0d11c2 /drivers/usb/host/whci/pzl.c
parentb41ecf9a80a55406eb4bf90c1ba260785002e103 (diff)
downloadlinux-171b37ee95865c052a88d52a05895c3c584f4871.tar.xz
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)
struct whc_urb *wurb = urb->hcpriv;
struct whc_qset *qset = wurb->qset;
struct whc_std *std, *t;
+ bool has_qtd = false;
int ret;
unsigned long flags;
@@ -343,17 +344,22 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
goto out;
list_for_each_entry_safe(std, t, &qset->stds, list_node) {
- if (std->urb == urb)
+ if (std->urb == urb) {
+ if (std->qtd)
+ has_qtd = true;
qset_free_std(whc, std);
- else
+ } else
std->qtd = NULL; /* so this std is re-added when the qset is */
}
- pzl_qset_remove(whc, qset);
- wurb->status = status;
- wurb->is_async = false;
- queue_work(whc->workqueue, &wurb->dequeue_work);
-
+ if (has_qtd) {
+ pzl_qset_remove(whc, qset);
+ update_pzl_hw_view(whc);
+ wurb->status = status;
+ wurb->is_async = false;
+ queue_work(whc->workqueue, &wurb->dequeue_work);
+ } else
+ qset_remove_urb(whc, qset, urb, status);
out:
spin_unlock_irqrestore(&whc->lock, flags);