diff options
author | hselasky <hselasky@FreeBSD.org> | 2011-12-14 00:28:54 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2011-12-14 00:28:54 +0000 |
commit | 7076389cec83009f9046b6c6e2695fe340a63802 (patch) | |
tree | 56520f5d0635d8db6259b372fff280b4e6288da5 /sys/dev/usb/controller/uhci.c | |
parent | 145914e3e7153161b6dd67fdcd58c7a8201845bc (diff) | |
download | FreeBSD-src-7076389cec83009f9046b6c6e2695fe340a63802.zip FreeBSD-src-7076389cec83009f9046b6c6e2695fe340a63802.tar.gz |
Implement better support for USB controller suspend and resume.
This patch should remove the need for kldunload of USB
controller drivers at suspend and kldload of USB controller
drivers at resume.
This patch also fixes some build issues in avr32dci.c
MFC after: 2 weeks
Diffstat (limited to 'sys/dev/usb/controller/uhci.c')
-rw-r--r-- | sys/dev/usb/controller/uhci.c | 56 |
1 files changed, 29 insertions, 27 deletions
diff --git a/sys/dev/usb/controller/uhci.c b/sys/dev/usb/controller/uhci.c index c365e01..d9091c9 100644 --- a/sys/dev/usb/controller/uhci.c +++ b/sys/dev/usb/controller/uhci.c @@ -373,9 +373,10 @@ done_1: done_2: - /* reload the configuration */ - UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum); - UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof); + /* reset frame number */ + UWRITE2(sc, UHCI_FRNUM, 0); + /* set default SOF value */ + UWRITE1(sc, UHCI_SOF, 0x40); USB_BUS_UNLOCK(&sc->sc_bus); @@ -463,9 +464,6 @@ uhci_init(uhci_softc_t *sc) uhci_dumpregs(sc); } #endif - sc->sc_saved_sof = 0x40; /* default value */ - sc->sc_saved_frnum = 0; /* default frame number */ - /* * Setup QH's */ @@ -658,24 +656,16 @@ uhci_init(uhci_softc_t *sc) return (0); } -/* NOTE: suspend/resume is called from - * interrupt context and cannot sleep! - */ - -void +static void uhci_suspend(uhci_softc_t *sc) { - USB_BUS_LOCK(&sc->sc_bus); - #ifdef USB_DEBUG if (uhcidebug > 2) { uhci_dumpregs(sc); } #endif - /* save some state if BIOS doesn't */ - sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM); - sc->sc_saved_sof = UREAD1(sc, UHCI_SOF); + USB_BUS_LOCK(&sc->sc_bus); /* stop the controller */ @@ -685,13 +675,10 @@ uhci_suspend(uhci_softc_t *sc) UHCICMD(sc, UHCI_CMD_EGSM); - usb_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_RESUME_WAIT)); - USB_BUS_UNLOCK(&sc->sc_bus); } -void +static void uhci_resume(uhci_softc_t *sc) { USB_BUS_LOCK(&sc->sc_bus); @@ -704,21 +691,17 @@ uhci_resume(uhci_softc_t *sc) UHCICMD(sc, UHCI_CMD_FGR); - usb_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_RESUME_DELAY)); - /* and start traffic again */ uhci_start(sc); + USB_BUS_UNLOCK(&sc->sc_bus); + #ifdef USB_DEBUG - if (uhcidebug > 2) { + if (uhcidebug > 2) uhci_dumpregs(sc); - } #endif - USB_BUS_UNLOCK(&sc->sc_bus); - /* catch lost interrupts */ uhci_do_poll(&sc->sc_bus); } @@ -3179,6 +3162,24 @@ uhci_device_suspend(struct usb_device *udev) } static void +uhci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) +{ + struct uhci_softc *sc = UHCI_BUS2SC(bus); + + switch (state) { + case USB_HW_POWER_SUSPEND: + case USB_HW_POWER_SHUTDOWN: + uhci_suspend(sc); + break; + case USB_HW_POWER_RESUME: + uhci_resume(sc); + break; + default: + break; + } +} + +static void uhci_set_hw_power(struct usb_bus *bus) { struct uhci_softc *sc = UHCI_BUS2SC(bus); @@ -3225,6 +3226,7 @@ struct usb_bus_methods uhci_bus_methods = .device_resume = uhci_device_resume, .device_suspend = uhci_device_suspend, .set_hw_power = uhci_set_hw_power, + .set_hw_power_sleep = uhci_set_hw_power_sleep, .roothub_exec = uhci_roothub_exec, .xfer_poll = uhci_do_poll, }; |