--- 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)