+ struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
+ u32 sts = readl(&cntl->regs->roothub_portstatus[port]);
+ if (!(sts & RH_PS_CCS))
+ // No device.
+ return -1;
+
+ // XXX - need to wait for USB_TIME_ATTDB if just powered up?
+
+ return 0;
+}
+
+// Disable port
+static void
+ohci_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
+ writel(&cntl->regs->roothub_portstatus[port], RH_PS_CCS|RH_PS_LSDA);
+}
+
+// Reset device on port
+static int
+ohci_hub_reset(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
+ writel(&cntl->regs->roothub_portstatus[port], RH_PS_PRS);
+ u32 sts;
+ u64 end = calc_future_tsc(USB_TIME_DRSTR * 2);
+ for (;;) {
+ sts = readl(&cntl->regs->roothub_portstatus[port]);
+ if (!(sts & RH_PS_PRS))
+ // XXX - need to ensure USB_TIME_DRSTR time in reset?
+ break;
+ if (check_tsc(end)) {
+ // Timeout.
+ warn_timeout();
+ ohci_hub_disconnect(hub, port);
+ return -1;
+ }
+ yield();
+ }
+
+ if ((sts & (RH_PS_CCS|RH_PS_PES)) != (RH_PS_CCS|RH_PS_PES))
+ // Device no longer present
+ return -1;
+
+ return !!(sts & RH_PS_LSDA);
+}
+
+static struct usbhub_op_s ohci_HubOp = {
+ .detect = ohci_hub_detect,
+ .reset = ohci_hub_reset,
+ .disconnect = ohci_hub_disconnect,
+};
+
+// Find any devices connected to the root hub.
+static int
+check_ohci_ports(struct usb_ohci_s *cntl)
+{
+ ASSERT32FLAT();
+ // Turn on power for all devices on roothub.
+ u32 rha = readl(&cntl->regs->roothub_a);
+ rha &= ~(RH_A_PSM | RH_A_OCPM);
+ writel(&cntl->regs->roothub_status, RH_HS_LPSC);
+ writel(&cntl->regs->roothub_b, RH_B_PPCM);
+ msleep((rha >> 24) * 2);
+ // XXX - need to sleep for USB_TIME_SIGATT if just powered up?
+
+ struct usbhub_s hub;
+ memset(&hub, 0, sizeof(hub));
+ hub.cntl = &cntl->usb;
+ hub.portcount = rha & RH_A_NDP;
+ hub.op = &ohci_HubOp;
+ usb_enumerate(&hub);
+ return hub.devcount;
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static int
+start_ohci(struct usb_ohci_s *cntl, struct ohci_hcca *hcca)
+{
+ u32 oldfminterval = readl(&cntl->regs->fminterval);
+ u32 oldrwc = readl(&cntl->regs->control) & OHCI_CTRL_RWC;