diff options
| author | David Brownell <david-b@pacbell.net> | 2003-07-15 00:53:20 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <greg@kroah.com> | 2003-07-15 00:53:20 -0700 |
| commit | ddae9dee28816fdab8ff41d5dae05d1d9fef6a3a (patch) | |
| tree | b4690e618489a2eae6428db9019ae4cb0e7ddca1 | |
| parent | 8d0c9758a008d15084b914ff0b1e7dd4e0ba7aec (diff) | |
[PATCH] USB: ohci minor tweaks
Two small updates:
- Report short control reads correctly in an exotic case
that our regression tests cover. (Haven't run them with
ohci for a long time, it seems...)
- IRQ non-delivery bugs (ACPI, APIC, etc) can prevent urbs
from unlinking. This prints a warning when that sort of
non-USB bug is biting.
| -rw-r--r-- | drivers/usb/host/ohci-hcd.c | 3 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-q.c | 10 |
2 files changed, 13 insertions, 0 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index d00701ae90d6..8d7a0657140d 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -319,6 +319,7 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep) int epnum = ep & USB_ENDPOINT_NUMBER_MASK; unsigned long flags; struct ed *ed; + unsigned limit = 1000; /* ASSERT: any requests/urbs are being unlinked */ /* ASSERT: nobody can be submitting urbs for this any more */ @@ -337,6 +338,8 @@ rescan: ed->state = ED_IDLE; switch (ed->state) { case ED_UNLINK: /* wait for hw to finish? */ + /* major IRQ delivery trouble loses INTR_SF too... */ + WARN_ON (limit-- == 0); spin_unlock_irqrestore (&ohci->lock, flags); set_current_state (TASK_UNINTERRUPTIBLE); schedule_timeout (1); diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 98116434c8e5..e44e9f931fa9 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -43,6 +43,16 @@ finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs) spin_lock (&urb->lock); if (likely (urb->status == -EINPROGRESS)) urb->status = 0; + /* report short control reads right even though the data TD always + * has TD_R set. (much simpler, but creates the 1-td limit.) + */ + if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK) + && unlikely (usb_pipecontrol (urb->pipe)) + && urb->actual_length < urb->transfer_buffer_length + && usb_pipein (urb->pipe) + && urb->status == 0) { + urb->status = -EREMOTEIO; + } spin_unlock (&urb->lock); // what lock protects these? |
