|
@@ -41,9 +41,13 @@ finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)
|
|
|
__releases(ohci->lock)
|
|
|
__acquires(ohci->lock)
|
|
|
{
|
|
|
- struct device *dev = ohci_to_hcd(ohci)->self.controller;
|
|
|
+ struct device *dev = ohci_to_hcd(ohci)->self.controller;
|
|
|
+ struct usb_host_endpoint *ep = urb->ep;
|
|
|
+ struct urb_priv *urb_priv;
|
|
|
+
|
|
|
// ASSERT (urb->hcpriv != 0);
|
|
|
|
|
|
+ restart:
|
|
|
urb_free_priv (ohci, urb->hcpriv);
|
|
|
urb->hcpriv = NULL;
|
|
|
if (likely(status == -EINPROGRESS))
|
|
@@ -80,6 +84,21 @@ __acquires(ohci->lock)
|
|
|
ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE);
|
|
|
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
|
|
|
}
|
|
|
+
|
|
|
+ /*
|
|
|
+ * An isochronous URB that is sumitted too late won't have any TDs
|
|
|
+ * (marked by the fact that the td_cnt value is larger than the
|
|
|
+ * actual number of TDs). If the next URB on this endpoint is like
|
|
|
+ * that, give it back now.
|
|
|
+ */
|
|
|
+ if (!list_empty(&ep->urb_list)) {
|
|
|
+ urb = list_first_entry(&ep->urb_list, struct urb, urb_list);
|
|
|
+ urb_priv = urb->hcpriv;
|
|
|
+ if (urb_priv->td_cnt > urb_priv->length) {
|
|
|
+ status = 0;
|
|
|
+ goto restart;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
@@ -546,7 +565,6 @@ td_fill (struct ohci_hcd *ohci, u32 info,
|
|
|
td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000);
|
|
|
*ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci,
|
|
|
(data & 0x0FFF) | 0xE000);
|
|
|
- td->ed->last_iso = info & 0xffff;
|
|
|
} else {
|
|
|
td->hwCBP = cpu_to_hc32 (ohci, data);
|
|
|
}
|
|
@@ -996,7 +1014,7 @@ rescan_this:
|
|
|
urb_priv->td_cnt++;
|
|
|
|
|
|
/* if URB is done, clean up */
|
|
|
- if (urb_priv->td_cnt == urb_priv->length) {
|
|
|
+ if (urb_priv->td_cnt >= urb_priv->length) {
|
|
|
modified = completed = 1;
|
|
|
finish_urb(ohci, urb, 0);
|
|
|
}
|
|
@@ -1086,7 +1104,7 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td)
|
|
|
urb_priv->td_cnt++;
|
|
|
|
|
|
/* If all this urb's TDs are done, call complete() */
|
|
|
- if (urb_priv->td_cnt == urb_priv->length)
|
|
|
+ if (urb_priv->td_cnt >= urb_priv->length)
|
|
|
finish_urb(ohci, urb, status);
|
|
|
|
|
|
/* clean schedule: unlink EDs that are no longer busy */
|