--- sys/dev/usb/ohci.c.orig	Wed Mar  5 22:17:15 2003
+++ sys/dev/usb/ohci.c	Thu Jun 19 06:15:43 2003
@@ -998,7 +998,9 @@
 	DPRINTF(("ohci_shutdown: stopping the HC\n"));
 	OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
 }
+#endif
 
+#if defined(OHCI_RESUME_SUPPORT) || defined(__NetBSD__) || defined(__OpenBSD__)
 /*
  * Handle suspend/resume.
  *
@@ -1021,7 +1023,9 @@
 	s = splhardusb();
 	switch (why) {
 	case PWR_SUSPEND:
+#if defined(__NetBSD__) || defined(__OpenBSD__)
 	case PWR_STANDBY:
+#endif
 		sc->sc_bus.use_polling++;
 		ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK;
 		if (sc->sc_control == 0) {
@@ -1039,6 +1043,72 @@
 		break;
 	case PWR_RESUME:
 		sc->sc_bus.use_polling++;
+#ifdef OHCI_REINIT_IN_RESUME
+		/* Reinitialize OHCI */
+		{
+		u_int32_t ival, hcr, fm, per, desca;
+		int i;
+
+		/* reset OHCI */
+		OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
+		usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY);
+
+		/* We now own the host controller and the bus has been reset. */
+		ival = OHCI_GET_IVAL(OREAD4(sc, OHCI_FM_INTERVAL));
+
+		OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */
+		/* Nominal time for a reset is 10 us. */
+		for (i = 0; i < 10; i++) {
+			delay(10);
+			hcr = OREAD4(sc, OHCI_COMMAND_STATUS) &
+				OHCI_HCR;
+			if (!hcr)
+				break;
+		}
+		/* Set up HC registers. */
+		OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0));
+		OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr);
+		OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr);
+		/* disable all interrupts and then switch on all desired
+		   interrupts */
+		OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
+		OWRITE4(sc, OHCI_INTERRUPT_ENABLE,
+				sc->sc_intre & (OHCI_ALL_INTRS | OHCI_MIE));
+		/* switch on desired functional features */
+		ctl = OREAD4(sc, OHCI_CONTROL);
+		ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR);
+		ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE |
+			OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL;
+		/* And finally start it! */
+		OWRITE4(sc, OHCI_CONTROL, ctl);
+
+		/*
+		 * The controller is now OPERATIONAL.  Set a some final
+		 * registers that should be set earlier, but that the
+		 * controller ignores when in the SUSPEND state.
+		 */
+		fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT;
+		fm |= OHCI_FSMPS(ival) | ival;
+		OWRITE4(sc, OHCI_FM_INTERVAL, fm);
+		per = OHCI_PERIODIC(ival); /* 90% periodic */
+		OWRITE4(sc, OHCI_PERIODIC_START, per);
+
+		/* Fiddle the No OverCurrent Protection bit to avoid chip
+		   bug. */
+		desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A);
+		OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP);
+		OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */
+		usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY);
+		OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca);
+
+		/*
+		 * The AMD756 requires a delay before re-reading the register,
+		 * otherwise it will occasionally report 0 ports.
+		 */
+		usb_delay_ms(&sc->sc_bus, OHCI_READ_DESC_DELAY);
+		sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A));
+		}
+#else /* not OHCI_REINIT_IN_RESUME */
 		/* Some broken BIOSes do not recover these values */
 		OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0));
 		OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr);
@@ -1056,13 +1126,16 @@
 		ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL;
 		OWRITE4(sc, OHCI_CONTROL, ctl);
 		usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
+#endif /* OHCI_REINIT_IN_RESUME */
 		sc->sc_control = sc->sc_intre = 0;
 		sc->sc_bus.use_polling--;
 		break;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
 	case PWR_SOFTSUSPEND:
 	case PWR_SOFTSTANDBY:
 	case PWR_SOFTRESUME:
 		break;
+#endif
 	}
 	splx(s);
 }
--- sys/dev/usb/ohci_pci.c.orig	Fri Feb 28 22:21:17 2003
+++ sys/dev/usb/ohci_pci.c	Thu Jun 19 05:30:18 2003
@@ -114,6 +114,36 @@
 
 static int ohci_pci_attach(device_t self);
 static int ohci_pci_detach(device_t self);
+#ifdef OHCI_RESUME_SUPPORT
+static int ohci_pci_suspend(device_t self);
+static int ohci_pci_resume(device_t self);
+
+
+static int
+ohci_pci_suspend(device_t self)
+{
+	ohci_softc_t *sc = device_get_softc(self);
+	int err;
+
+	err = bus_generic_suspend(self);
+	if (err)
+		return err;
+	ohci_power(PWR_SUSPEND, sc);
+
+	return 0;
+}
+
+static int
+ohci_pci_resume(device_t self)
+{
+	ohci_softc_t *sc = device_get_softc(self);
+
+	ohci_power(PWR_RESUME, sc);
+	bus_generic_resume(self);
+
+	return 0;
+}
+#endif /* OHCI_RESUME_SUPPORT */
 
 static const char *
 ohci_pci_match(device_t self)
@@ -297,6 +327,10 @@
 	/* Device interface */
 	DEVMETHOD(device_probe, ohci_pci_probe),
 	DEVMETHOD(device_attach, ohci_pci_attach),
+#ifdef OHCI_RESUME_SUPPORT
+	DEVMETHOD(device_suspend, ohci_pci_suspend),
+	DEVMETHOD(device_resume, ohci_pci_resume),
+#endif
 	DEVMETHOD(device_shutdown, bus_generic_shutdown),
 
 	/* Bus interface */
--- sys/dev/usb/ohcivar.h.orig	Tue Oct  1 02:50:16 2002
+++ sys/dev/usb/ohcivar.h	Thu Jun 19 06:14:15 2003
@@ -38,6 +38,9 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#define OHCI_RESUME_SUPPORT 	1 /* Enable resume support on FreeBSD */
+#define OHCI_REINIT_IN_RESUME	1 /* OHCI reinitialize in resuming */
+
 typedef struct ohci_soft_ed {
 	ohci_ed_t ed;
 	struct ohci_soft_ed *next;
@@ -158,6 +161,9 @@
 #if defined(__NetBSD__) || defined(__OpenBSD__)
 int		ohci_detach(ohci_softc_t *, int);
 int		ohci_activate(device_ptr_t, enum devact);
+#endif
+#if defined(__FreeBSD__) && defined(OHCI_RESUME_SUPPORT)
+void		ohci_power(int, void *);
 #endif
 
 #define MS_TO_TICKS(ms) ((ms) * hz / 1000)
