aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
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
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')
-rw-r--r--drivers/usb/host/whci/asl.c19
-rw-r--r--drivers/usb/host/whci/pzl.c20
2 files changed, 25 insertions, 14 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
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