frame &= ~(ed->interval - 1);
frame |= ed->branch;
urb->start_frame = frame;
+ }
+ } else if (ed->type == PIPE_ISOCHRONOUS) {
+ u16 next = ohci_frame_no(ohci) + 2;
+ u16 frame = ed->last_iso + ed->interval;
+
+ /* Behind the scheduling threshold? */
+ if (unlikely(tick_before(frame, next))) {
+
+ /* USB_ISO_ASAP: Round up to the first available slot */
+ if (urb->transfer_flags & URB_ISO_ASAP)
+ frame += (next - frame + ed->interval - 1) &
+ -ed->interval;
+
+ /*
+ * Not ASAP: Use the next slot in the stream. If
+ * the entire URB falls before the threshold, fail.
+ */
+ else if (tick_before(frame + ed->interval *
+ (urb->number_of_packets - 1), next)) {
+ retval = -EXDEV;
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ goto fail;
+ }
- /* yes, only URB_ISO_ASAP is supported, and
- * urb->start_frame is never used as input.
+ /*
+ * Some OHCI hardware doesn't handle late TDs
+ * correctly. After retiring them it proceeds to
+ * the next ED instead of the next TD. Therefore
+ * we have to omit the late TDs entirely.
*/
+ urb_priv->td_cnt = DIV_ROUND_UP(next - frame,
+ ed->interval);
}
- } else if (ed->type == PIPE_ISOCHRONOUS)
- urb->start_frame = ed->last_iso + ed->interval;
+ urb->start_frame = frame;
+ }
/* fill the TDs and link them to the ed; and
* enable that part of the schedule, if needed
#endif
+#ifdef CONFIG_PM
+
+static int __maybe_unused ohci_suspend(struct usb_hcd *hcd, bool do_wakeup)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ unsigned long flags;
+ int rc = 0;
+
+ /* Root hub was already suspended. Disable irq emission and
+ * mark HW unaccessible, bail out if RH has been resumed. Use
+ * the spinlock to properly synchronize with possible pending
+ * RH suspend or resume activity.
+ */
+ spin_lock_irqsave (&ohci->lock, flags);
+ if (ohci->rh_state != OHCI_RH_SUSPENDED) {
+ rc = -EINVAL;
+ goto bail;
+ }
+ ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+ (void)ohci_readl(ohci, &ohci->regs->intrdisable);
+
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ bail:
+ spin_unlock_irqrestore (&ohci->lock, flags);
+
+ return rc;
+}
+
+
+static int __maybe_unused ohci_resume(struct usb_hcd *hcd, bool hibernated)
+{
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ /* Make sure resume from hibernation re-enumerates everything */
+ if (hibernated)
+ ohci_usb_reset(hcd_to_ohci(hcd));
+
+ ohci_finish_controller_resume(hcd);
+ return 0;
+}
+
+#endif
+
/*-------------------------------------------------------------------------*/
MODULE_AUTHOR (DRIVER_AUTHOR);
#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver
#endif
-#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
-#include "ohci-ppc-soc.c"
-#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver
-#endif
-
#ifdef CONFIG_ARCH_AT91
#include "ohci-at91.c"
#define PLATFORM_DRIVER ohci_hcd_at91_driver